题意:
给出已0 1染色的无向图(不一定联通),一次操作为一对相邻点颜色互换.
问使任意相邻点颜色不同,最少需要多少次操作
分析:
交换两点的代价即为两点间最短路.
故用BFS找出所有点到任意点的最短距离,并记录路径.
对于每个连通块,按照相邻点颜色不同重新染色一遍,若发现已给的01数目与染色需要01数目不符,则不可能
不然 ,则根据已给的01数目与染色需要01数目,确定匹配的点集.
最后KM算法算出最小权值匹配即可
确定匹配后,分析下同一路上的交换顺序,确定交换步骤
不算难,就是麻烦
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 #include <vector> 6 using namespace std; 7 const int INF=0x3f3f3f3f; 8 const int MAXN=505; 9 const int MAXM = 505*505; 10 11 int map[MAXN][MAXN];//二分图描述 12 int linker[MAXN],lx[MAXN],ly[MAXN]; 13 int slack[MAXN]; 14 int nx,ny; 15 bool visx[MAXN],visy[MAXN]; 16 17 bool DFS(int x) 18 { 19 int y; 20 visx[x] = 1; 21 for(y = 0;y < ny; ++y) 22 { 23 if(visy[y]) continue; 24 int tmp = lx[x] + ly[y] - map[x][y]; 25 if(tmp == 0) 26 { 27 visy[y] = 1; 28 if(linker[y] == -1 || DFS(linker[y])) 29 { 30 linker[y] = x; 31 return 1; 32 } 33 } 34 else if(slack[y] > tmp) 35 slack[y] = tmp; 36 } 37 return 0; 38 } 39 int KM() 40 { 41 for(int i = 0;i < nx; ++i) linker[i] = -1,ly[i] = 0; 42 for(int i = 0;i < nx; ++i) 43 { 44 lx[i] = -INF; 45 for(int j = 0;j < ny; ++j) 46 if(map[i][j] > lx[i]) 47 lx[i] = map[i][j]; 48 } 49 for(int x = 0;x < nx; ++x) 50 { 51 for(int i = 0;i < ny; ++i) slack[i] = INF; 52 while(1) 53 { 54 for(int i = 0;i < nx; ++i) visx[i] = 0; 55 for(int i = 0;i < ny; ++i) visy[i] = 0; 56 if(DFS(x)) break; 57 int d = INF; 58 for(int i = 0;i < ny; ++i) 59 if(!visy[i] && d > slack[i]) 60 d = slack[i]; 61 for(int i = 0;i < nx; ++i) 62 if(visx[i]) 63 lx[i] -= d; 64 for(int i = 0;i < ny; ++i) 65 if(visy[i]) ly[i] += d; 66 else slack[i] -= d; 67 } 68 } 69 int res = 0; 70 for(int i = 0;i < ny;++i) 71 if(linker[i] != -1) 72 res += map[ linker[i] ][i]; 73 return res; 74 } 75 76 int g[MAXN][MAXN],col[MAXN]; 77 vector<int> X,Y,Left,Right;//X 1 Y 0 78 char s[MAXN]; 79 int n,m,ans; 80 queue<int> p; 81 vector<int> G[MAXN]; 82 83 bool BFS(int x,int c)//染色 84 { 85 while(!p.empty()) p.pop(); 86 col[x] = c; 87 if(c) X.push_back(x); 88 else Y.push_back(x); 89 p.push(x); 90 int size,i; 91 while(!p.empty()) 92 { 93 x = p.front(); p.pop(); 94 size = G[x].size(); 95 for(i = 0; i < size; ++i) 96 { 97 if(col[ G[x][i] ] == col[x] ) return 0; 98 else if(col[ G[x][i] ] == -1) 99 { 100 col[ G[x][i] ] = col[x]^1; 101 if( col[ G[x][i] ] ) X.push_back( G[x][i] );//1 102 else Y.push_back( G[x][i] );//0 103 p.push( G[x][i] ); 104 } 105 } 106 } 107 return 1; 108 } 109 vector<int> path[MAXN][MAXN]; 110 int vis[MAXN],Pair1[MAXN],Pair2[MAXN],*Pair; 111 pair<int,int> Ans[MAXM];//答案 112 113 void GetPath(int u)//找到最短路并记录路径 114 { 115 int i, t, v; 116 for(i = 0; i <= n; ++i) vis[i] = 0; 117 while(!p.empty()) p.pop(); 118 p.push(u); 119 path[u][u].push_back(u); 120 vis[u] = 1; 121 g[u][u] = 0; 122 while(!p.empty()) 123 { 124 t = p.front(); p.pop(); 125 for(i = 0; i < G[t].size(); ++i) 126 { 127 v = G[t][i]; 128 if( !vis[v] ) 129 { 130 vis[v] = 1; 131 g[u][v] = g[u][t] + 1; 132 path[u][v] = path[u][t]; 133 path[u][v].push_back(v); 134 p.push(v); 135 } 136 } 137 } 138 } 139 int GetSum(vector<int> &X,vector<int> &Y,int Pair[])//匹配 140 { 141 int i,j; 142 Left.clear(); Right.clear(); 143 for( i = 0; i < X.size(); ++i) 144 { 145 if(s[ X[i] ] == ‘0‘) Left.push_back( X[i] ); 146 } 147 for( i = 0; i < Y.size(); ++i) 148 { 149 if(s[ Y[i] ] == ‘1‘) Right.push_back( Y[i] ); 150 } 151 nx = Left.size(); 152 ny = Right.size(); 153 for( i = 0; i< nx; ++i) 154 { 155 for( j = 0;j< ny; ++j) 156 { 157 int x = Left[i],y = Right[j]; 158 map[i][j] = -g[x][y]; 159 } 160 } 161 int sum = KM(); 162 for(i = 0; i < nx; ++i) 163 { 164 int v = Right[i] ; 165 int u = Left[ linker[i] ]; 166 Pair[u] = v; Pair[v] = u;//1 0 167 } 168 return -sum; 169 } 170 void GetAns(int u,int v) 171 { 172 int i, j, k; 173 if(s[u] != ‘0‘) swap( u, v); 174 vector<int> &p = path[u][v]; 175 for(i = 0; i < p.size(); i = j) 176 { 177 for(j = i; j<p.size() && s[ p[j] ] == ‘0‘; ++j); //路上第一个‘1‘ 178 if(j == p.size()) break; 179 for(k = j; k > i; --k) 180 { 181 Ans[ans++] = make_pair(p[k], p[k - 1]); 182 swap(s[ p[k] ],s[ p[k-1] ]); 183 } 184 } 185 } 186 int solve(int st)//当前连通分支 187 { 188 int i, zero = 0, col0 = 0; 189 X.clear(); Y.clear(); 190 if(!BFS(st, 0)) return 0;//染色 191 for(i = 0; i < X.size(); ++i) 192 { 193 if(s[X[i]] == ‘0‘) ++zero; 194 } 195 for(i = 0; i < Y.size(); ++i) 196 { 197 if(s[Y[i]] == ‘0‘) ++zero; 198 } 199 int sum1=INF,sum2=INF; 200 if(zero == Y.size() )// ‘0‘ 与 0 的数目相等,X中‘0‘与Y中‘1‘对换 201 { 202 sum1 = GetSum(X, Y, Pair1); 203 } 204 if(zero == X.size() )// ‘0‘ 与 1 的数目相等,X中‘1‘与Y中‘0‘对换 205 { 206 sum2 = GetSum(Y, X, Pair2); 207 } 208 if(sum1 == INF && sum2 == INF) return 0; 209 if(sum1 < sum2) Pair = Pair1; 210 else Pair = Pair2; 211 for(i=0;i<X.size(); ++i) 212 { 213 if(Pair[ X[i] ] != -1) GetAns(X[i], Pair[ X[i] ]); 214 } 215 return 1; 216 } 217 int main() 218 { 219 int i,j,t; 220 scanf("%d", &t); 221 while(t--) 222 { 223 scanf("%d%d%s", &n, &m, s+1); 224 for(i = 1; i <= n; ++i) G[i].clear(); 225 for(i = 1; i <= n; ++i) 226 { 227 for(j = 1; j <= n; ++j) 228 { 229 g[i][j] = INF; 230 } 231 } 232 for(i = 1;i <= m; ++i) 233 { 234 int x,y; 235 scanf("%d%d", &x, &y); 236 G[x].push_back(y); 237 G[y].push_back(x); 238 } 239 for(i = 1; i <= n; ++i) 240 for(j = 1; j <= n; ++j) 241 path[i][j].clear(); 242 for(i = 1; i <= n; ++i) GetPath(i);//最短路 243 for(i = 1; i <= n; ++i) 244 { 245 Pair1[i] = Pair2[i] = col[i] = -1; 246 } 247 bool flag=1; 248 ans = 0; 249 for(i = 1;i <= n; ++i)//对每个连通分支 250 { 251 if(col[i]==-1&&!solve(i)) 252 { 253 flag = 0; break; 254 } 255 } 256 if(!flag) 257 { 258 puts("-1"); continue; 259 } 260 printf("%d\n",ans); 261 for(i = 0; i< ans ;++i) 262 printf("%d %d\n",Ans[i].first, Ans[i].second); 263 } 264 return 0; 265 }
时间: 2024-10-29 19:10:49