题目大意:
选定一些格子保证景点对应的格子通过这些格子连通,保证选定的所有格子对应的权值和最小
这是相当于理解为将所有点形成的最小生成树
这里点的个数很少,所以可以对每一个点进行状态压缩
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 }
时间: 2024-10-12 13:38:58