题目大意:

选定一些格子保证景点对应的格子通过这些格子连通,保证选定的所有格子对应的权值和最小

 

这是相当于理解为将所有点形成的最小生成树

这里点的个数很少,所以可以对每一个点进行状态压缩

f[st][i]表示连通性至少为st,且经过i点的最小距离

方程1.f[st][i] = Min{f[s][i] + f[st - s][i]}(s为st的子集)

方程2.f[st][i] = Min{f[st][j] + w(i,j)}(i,j之间有边相连)

那么可以看出来大的状态总是跟小的状态有关,那么总是先求出小的状态集合

利用spfa求解所有状态对应的点跑最短路对其他格点进行松弛

我到现在也不知道为什么这样写效率会高

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <queue>
  5 using namespace std;
  6 typedef pair<int,int> pii;
  7 #define N 11
  8 const int MAXN=1<<N;
  9 const int INF = 0x3f3f3f3f;
 10 int n , m ;
 11 
 12 struct Node{
 13     int x , y , s;
 14     Node(){}
 15     Node(int x , int y , int s):x(x),y(y),s(s){}
 16 };
 17 Node pre[N][N][MAXN];//用于回溯找上一个节点
 18 
 19 int w[N][N] , dp[N][N][MAXN] , dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
 20 bool vis[N][N] , flag[N][N];
 21 queue<pii> que;
 22 
 23 bool ok(int x , int y){return x>=1&&x<=n&&y>=1&&y<=m;}
 24 
 25 void spfa(int state)
 26 {
 27     while(!que.empty()){
 28         pii u = que.front();
 29         que.pop();
 30         int x = u.first , y = u.second;
 31         vis[x][y] = false;
 32         for(int i=0 ; i<4 ; i++){
 33             int xx = x+dir[i][0] , yy = y+dir[i][1];
 34             if(!ok(xx,yy)) continue;
 35             if(dp[xx][yy][state]>dp[x][y][state]+w[xx][yy]){
 36                 dp[xx][yy][state]=dp[x][y][state]+w[xx][yy];
 37                 pre[xx][yy][state] = Node(x , y , state);
 38                 if(!vis[xx][yy]) que.push(make_pair(xx , yy));
 39             }
 40         }
 41     }
 42 }
 43 
 44 void huisu(int x , int y , int s)
 45 {
 46     flag[x][y] = true;
 47     if(pre[x][y][s].s == 0) return;
 48     huisu(pre[x][y][s].x , pre[x][y][s].y , pre[x][y][s].s);
 49     if(pre[x][y][s].x==x && pre[x][y][s].y==y) huisu(pre[x][y][s].x , pre[x][y][s].y , s-pre[x][y][s].s);
 50 }
 51 
 52 void print()
 53 {
 54     for(int i=1 ; i<=n ; i++){
 55         for(int j=1 ; j<=m ; j++)
 56             if(!w[i][j]) printf("x");
 57             else if(flag[i][j]) printf("o");
 58             else printf("_");
 59         puts("");
 60     }
 61 }
 62 
 63 int main()
 64 {
 65    // freopen("in.txt" , "r" , stdin);
 66     while(~scanf("%d%d" , &n , &m))
 67     {
 68         int num = 0;
 69         memset(dp , 0x3f , sizeof(dp));
 70         memset(pre , 0 , sizeof(pre));
 71         for(int i=1 ; i<=n ; i++){
 72             for(int j=1 ; j<=m ; j++){
 73                 scanf("%d" , &w[i][j]);
 74                 if(!w[i][j]){
 75                     dp[i][j][1<<num] = 0;
 76                     num++;
 77                 }
 78             }
 79         }
 80         int ALL_STATE = 1<<num;
 81         for(int k=1 ; k<ALL_STATE ; k++){
 82             for(int i=1 ; i<=n ; i++){
 83                 for(int j=1 ; j<=m ; j++){
 84                     for(int s=(k-1)&k ; s ; s=(s-1)&k){
 85                         int tmps = k-s;
 86                         if(dp[i][j][k]>dp[i][j][s]+dp[i][j][tmps]-w[i][j]){
 87                             dp[i][j][k] = dp[i][j][s]+dp[i][j][tmps]-w[i][j];
 88                             pre[i][j][k] = Node(i , j , s);
 89                         }
 90                     }
 91                     if(dp[i][j][k]<INF) que.push(make_pair(i , j)) , vis[i][j]=true;
 92                 }
 93             }
 94             spfa(k);
 95         }
 96         memset(flag , 0 , sizeof(flag));
 97         for(int i=1 ; i<=n ; i++)
 98             for(int j=1 ; j<=m ; j++){
 99                 if(!w[i][j]){
100                     cout<<dp[i][j][ALL_STATE-1]<<endl;
101                     huisu(i , j , ALL_STATE-1);
102                     print();
103                     return 0;
104                 }
105             }
106 
107     }
108     return 0;
109 }

 

 posted on 2015-08-16 22:04  Love风吟  阅读(149)  评论(0编辑  收藏  举报