Problem:
Problem G:
Building Water Ways
In ancient times, Romans constructed numerous water ways to supply water to cities and industrial sites. These water ways were amongst the greatest engineering feats of the ancient world.
These water ways contributed to social infrastructures which improved people's quality of life. On the other hand, problems related to the water control and the water facilities are still interesting as a lot of games of water ways construction have been developed.
Your task is to write a program which reads a map and computes the minimum possible cost of constructing water ways from sources to all the cities.
As shown in Figure 1, the map is represented by
H
×
W
grid cells, where each cell represents source, city, flatland, or obstacle.
You can construct only one water way from a source, but there are no limitations on the length of that water way and it can provide water to any number of cities located on its path. You can not construct water ways on the obstacles.
Your objective is to bring water to all the city and minimize the number of cells which represent water ways. In the Figure 1, water ways are constructed in 14 cells which is the minimum cost.
The water ways must satisfy the following conditions:
a water way cell is adjacent to at most 2 water way cells in four cardinal points.
a source cell is adjacent to at most 1 water way cell in four cardinal points.
there is no path from a source to other sources through water ways.
Input
The input consists of multiple datasets. Each dataset consists of:
H W
H
×
W
characters
The integers
H
and
W
are the numbers of rows and columns of the map.
H
×
W
characters denote the cells which contain:
'
P
': source
'
*
': city
'
.
': flatland
'
#
': obstacle
The end of input is indicated by a line containing two zeros separated by a space.
Output
For each dataset, print the minimum cost to construct the water ways.
Constraints
Judge data contains at most 60 data sets.
3 ≤
H
,
W
≤ 10
1 ≤ the number of sources, the number of cities ≤ 8
The map is surrounded by obstacles.
Sources are not adjacent each other(on the left, right, top and bottom)
There is a solution.
Sample Input
3 8
########
#P....*#
########
10 10
##########
#P.......#
#..#*....#
#..#*.#.*#
#.....#*.#
#*.......#
#..##....#
#...#.P..#
#P......P#
##########
0 0
Output for the Sample Input
5
14

Submitted solutions:

code_snippet: #include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define _3_ 1

using namespace std;

typedef unsigned long long ull;
typedef pair<int,int> ii;

struct Point { int x,y; };

const int IINF = INT_MAX;
const char PATH = '$';

int h,w,s_size,c_size,bitIndex[12][12];
char c[12][12];
Point source[12],city[12],path[12];
int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};
int mini,blocks;
int bc[1<<9];

void dfs(int sp,int bitmask,int prev,int step,int depth){

  if( step+(c_size-bc[bitmask]) >= mini ) return;
  
  if( sp >= s_size ) return;

  if( bitmask == ((1<<c_size)-1) ) { mini = step; return; }

  bool next = 1;
  rep(dir,4){
    if( prev != -1 && ( prev + 2 ) % 4 == dir ) continue;
    int nx = path[sp].x + dx[dir], ny = path[sp].y + dy[dir];

    if( c[ny][nx] == 'P' || c[ny][nx] == '#' || c[ny][nx] == PATH ) continue;

    bool success = true;
    int cnt = 0;
    rep(i,4){
      int nx2 = nx + dx[i], ny2 = ny + dy[i];
      if( c[ny2][nx2] == PATH || c[ny2][nx2] == 'P' ) ++cnt;
    }
    if( cnt != 1 ) success = false;
    if( !success ) continue;
    
    Point pp = path[sp];
    char pc = c[ny][nx];
    int nbitmask = bitmask;
    bool fin = false;
    if( c[ny][nx] == '*' ) nbitmask |= (1<<bitIndex[ny][nx]), fin = true;

    path[sp] = (Point){nx,ny};
    c[ny][nx] = PATH;

    next = 0;
    dfs(sp,nbitmask,dir,step+1,depth+1);
    if( fin )dfs(sp+1,nbitmask,-1,step+1,0);

    path[sp] = pp;
    c[ny][nx] = pc;

    /*
     '*'?????£??\??????????????´????????????????????????????????????????????????????????????????????????????????????
     ????????§??¨???????????¨??????'*'????????????????????¨?????????
     */
    if( fin ) return; 

  }

  if( depth == 0 )  dfs(sp+1,bitmask,-1,step,0);  
} 

int compute(){
  mini = h*w-s_size - blocks;
  dfs(0,0,-1,0,0);
  return mini;
}



int main(){
  rep(i,(1<<9)) bc[i] = __builtin_popcount(i);
  while( scanf(" %d %d",&h,&w), h|w ){
    s_size = c_size = 0;
    blocks = 0;
    rep(i,h) rep(j,w) {
      scanf(" %c",&c[i][j]);
      if( c[i][j] == 'P' ) { source[s_size] = path[s_size] = (Point){j,i}; s_size++; }
      if( c[i][j] == '*' ) { city[c_size]   = (Point){j,i}; bitIndex[i][j] = c_size++; }
      if( c[i][j] == '#' ) ++blocks;
    }
    printf("%d\n",compute());
    //print_field(); puts("");
  }
  return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 1192
final_rank: 1

code_snippet: #include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define _3_ 1

using namespace std;

/*
  15:25 - 
  ?????????????????????????????????
  ??????????????????
  ??£??????
  ????????????????????¢????¨????
  ?????¨?????????????????????????°???????????????????????¶?????????????
  ---
  
  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?
  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?
  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?
  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?
  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?
  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?
  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?
  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?  _3_ < DO YOU HAVE THE TIME?
  _3_ IT'S A QUATER TO TEN >
  _3_ !!
  
*/

typedef unsigned long long ull;
typedef pair<int,int> ii;

struct Point { int x,y; };

const int IINF = INT_MAX;
const char PATH = '$';

int h,w,s_size,c_size,bitIndex[12][12];
char c[12][12];
Point source[12],city[12],path[12];
int limit,next_limit;
int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};
int mini;
int bc[1<<9];
int mani[12];

int initial_heuristic(){
  int sum = 0;
  rep(i,c_size) {
    mani[i] = IINF;
    rep(j,s_size) mani[i] = min(mani[i],abs(city[i].x-source[j].x)+abs(city[i].y-source[j].y));
    rep(j,c_size) if( j != i ) mani[i] = min(mani[i],abs(city[i].x-city[j].x)+abs(city[i].y-city[j].y));
     sum += mani[i];
  }
  return sum;
}


int get_heuristic(int sp,int bitmask){
  int sum = 0;
  rep(i,c_size) if( !( (bitmask>>i) & 1 ) ) {
    mani[i] = min(mani[i],abs(path[sp].x-city[i].x)+abs(path[sp].y-city[i].y));
    sum += mani[i];
  }
  return sum;
}


//typedef pair<ull,int> ullInt;
//map<ullInt,int> mincost; 
//unordered_map<ull,int> mincost; 
//map<ull,int> mincost; 
bool head[12][12];
bool opt[12][12];

int blocks;

void print_field(){
  rep(i,h) {
    rep(j,w){
      cout << c[i][j];
    } puts("");
  }
}

void dfs(int sp,int bitmask,int prev,int step,int depth){

  /*
  cout << "sp = " << sp << " step = " << step << endl;
  print_field(); puts("");
  */
  if( step+(c_size-bc[bitmask]) >= mini ) return;
  
  if( sp >= s_size ) return;

  if( bitmask == ((1<<c_size)-1) ) { 
    //print_field(); puts(""); 
    mini = step; return; }

  //int h = get_heuristic(sp,bitmask);
  //if( step+h >= mini ) return;

  bool next = 1;
  rep(dir,4){
    if( prev != -1 && ( prev + 2 ) % 4 == dir ) continue;
    int nx = path[sp].x + dx[dir], ny = path[sp].y + dy[dir];

    if( c[ny][nx] == 'P' || c[ny][nx] == '#' || c[ny][nx] == PATH ) continue;

    bool success = true;
    int cnt = 0;
    rep(i,4){
      int nx2 = nx + dx[i], ny2 = ny + dy[i];
      if( c[ny2][nx2] == PATH || c[ny2][nx2] == 'P' ) ++cnt;
    }
    if( cnt != 1 ) success = false;
    if( !success ) continue;
    
    Point pp = path[sp];
    char pc = c[ny][nx];
    int nbitmask = bitmask;
    bool fin = false;
    char prec = c[ny][nx];
    if( c[ny][nx] == '*' ) nbitmask |= (1<<bitIndex[ny][nx]), fin = true;

    path[sp] = (Point){nx,ny};
    c[ny][nx] = PATH;
    //short mini_temp[8];
    //rep(i,c_size) mini_temp[i] = mani[i];
    swap(head[path[sp].y][path[sp].x],head[ny][nx]);

    next = 0;
   
    dfs(sp,nbitmask,dir,step+1,depth+1);
    if( prec == '*' )dfs(sp+1,nbitmask,-1,step+1,0);

    //rep(i,c_size) mani[i] = mini_temp[i];
    swap(head[path[sp].y][path[sp].x],head[ny][nx]);
    path[sp] = pp;
    c[ny][nx] = pc;

    //if( c_size-(int)__builtin_popcount(bitmask) == 1 ) return false;
    if( fin ) return;
  }
  //if( c[path[sp].y][path[sp].x] == '*' || current_step == 0 ) dfs(sp+1,bitmask,-1,step,0);  
  //dfs(sp+1,bitmask,-1,step);  
  if( depth == 0 || c[path[sp].y][path[sp].x] == 'P' || c[path[sp].y][path[sp].x] == '*' )  dfs(sp+1,bitmask,-1,step,0);  
} 

int compute(){
  //initial_heuristic();
  mini = h*w-s_size - blocks;
  int csv = 0;
  dfs(0,0,-1,0,0);
  return mini;
}



int main(){
  srand((unsigned int)time(NULL));
  rep(i,(1<<9)) bc[i] = __builtin_popcount(i);
  while( scanf(" %d %d",&h,&w), h|w ){
    s_size = c_size = 0;
    blocks = 0;
    rep(i,h) rep(j,w) {
      head[i][j] = false;
      scanf(" %c",&c[i][j]);
      if( c[i][j] == 'P' ) { source[s_size] = path[s_size] = (Point){j,i}; s_size++; head[i][j] = true; }
      if( c[i][j] == '*' ) { city[c_size]   = (Point){j,i}; bitIndex[i][j] = c_size++; }
      if( c[i][j] == '#' ) ++blocks;
    }
    printf("%d\n",compute());
    //print_field(); puts("");
  }
  return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 1200
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define dump(...) cout<<"# "<<#__VA_ARGS__<<'='<<(__VA_ARGS__)<<endl
#define repi(i,a,b) for(int i=int(a);i<int(b);i++)
#define peri(i,a,b) for(int i=int(b);i-->int(a);)
#define rep(i,n) repi(i,0,n)
#define per(i,n) peri(i,0,n)
#define all(c) begin(c),end(c)
#define mp make_pair
#define mt make_tuple

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef vector<string> vs;

template<typename T1,typename T2>
ostream& operator<<(ostream& os,const pair<T1,T2>& p){
	return os<<'('<<p.first<<','<<p.second<<')';
}

template<typename Tuple>
void print_tuple(ostream&,const Tuple&){}
template<typename Car,typename... Cdr,typename Tuple>
void print_tuple(ostream& os,const Tuple& t){
	print_tuple<Cdr...>(os,t);
	os<<(sizeof...(Cdr)?",":"")<<get<sizeof...(Cdr)>(t);
}
template<typename... Args>
ostream& operator<<(ostream& os,const tuple<Args...>& t){
	print_tuple<Args...>(os<<'(',t);
	return os<<')';
}

template<typename Ch,typename Tr,typename C>
basic_ostream<Ch,Tr>& operator<<(basic_ostream<Ch,Tr>& os,const C& c){
	os<<'[';
	for(auto i=begin(c);i!=end(c);++i)
		os<<(i==begin(c)?"":" ")<<*i;
	return os<<']';
}

constexpr int INF=1e9;
constexpr int MOD=1e9+7;
constexpr double EPS=1e-9;

constexpr int di[]={-1,1,0,0},dj[]={0,0,-1,1};

int count(const vs& grid,int i,int j)
{
	int cnt=0;
	rep(k,4){
		int ni=i+di[k],nj=j+dj[k];
		cnt+=grid[ni][nj]=='P' || grid[ni][nj]=='W' || grid[ni][nj]=='C';
	}
	return cnt;
}

void print(const vs& grid)
{
	cout<<"# grid:"<<endl;
	for(const auto& line:grid) cout<<line<<endl;
}

void solve(vs& grid,const vector<pii>& ps,int pi,int cnt,int rest,int& res);

void dfs(vs& grid,int i,int j,const vector<pii>& ps,int pi,int cnt,int rest,int& res)
{
	if(cnt>=res) return;
	int h=grid.size(),w=grid[0].size();
	if(rest==0){
		int tmp=0;
		rep(i,h) rep(j,w) tmp+=grid[i][j]=='W' || grid[i][j]=='C';
		res=min(res,tmp);
	}
	if(grid[i][j]=='#' || grid[i][j]=='P' || count(grid,i,j)>=2) return;
	
	if(grid[i][j]=='*'){
		grid[i][j]='C';
		rep(k,4){
			int ni=i+di[k],nj=j+dj[k];
			dfs(grid,ni,nj,ps,pi,cnt+1,rest-1,res);
		}
		if(pi+1<ps.size()){
			int ni,nj; tie(ni,nj)=ps[pi+1];
			solve(grid,ps,pi+1,cnt+1,rest-1,res);
		}
		grid[i][j]='*';
	}
	else{
		grid[i][j]='W';
		rep(k,4){
			int ni=i+di[k],nj=j+dj[k];
			dfs(grid,ni,nj,ps,pi,cnt+1,rest,res);
		}
		grid[i][j]='.';
	}
}

void solve(vs& grid,const vector<pii>& ps,int pi,int cnt,int rest,int& res)
{
	if(pi==ps.size()) return;
	solve(grid,ps,pi+1,cnt,rest,res);
	int i,j; tie(i,j)=ps[pi];
	rep(k,4) dfs(grid,i+di[k],j+dj[k],ps,pi,cnt,rest,res);
}


int main()
{
	for(int h,w;cin>>h>>w && h|w;){
		vs grid(h);
		rep(i,h) cin>>grid[i];
		
		vector<pii> ps;
		rep(i,h) rep(j,w) if(grid[i][j]=='P') ps.emplace_back(i,j);
		
		int rest=0; rep(i,h) rep(j,w) rest+=grid[i][j]=='*';
		int res=INF;
		solve(grid,ps,0,0,rest,res);
		cout<<res<<endl;
	}
}
accuracy: 1
time_ms: 350
memory_kb: 1212
final_rank: 3