HDU 5740 - Glorious Brilliance

题意:

    给出已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

HDU 5740 - Glorious Brilliance的相关文章

HDU 3854 Glorious Array(树状数组)

题意:给一些结点,每个结点是黑色或白色,并有一个权值.定义两个结点之间的距离为两个结点之间结点的最小权值当两个结点异色时,否则距离为无穷大.给出两种操作,一种是将某个结点改变颜色,另一个操作是询问当前距离小于K的结点有多少对,K是一个定值. 思路:先求最初时候小于k的结点有多少对,然后每次改变颜色的时候,统计该点左侧和右侧各有多少同色和异色的结点(这一步使用树状数组),分别处理就行.另外需要预处理离某个结点最近的两个距离小于K的结点的位置. 代码写的略乱. #include<cstdio> #

Glorious Brilliance (最短路 + 带权二分图匹配)

这是一道代码大题.一开始读错题意了,然后理解成直接看上去的那种相邻,然后想不通好久!!! 把不同联通的图分离出来,然后先预处理一下形成之后的相邻图的状态,然后根据01确定哪一些是需要更换状态的,然后建图,利用二分图KM算法去匹配最优方案.然后求出每一组更换的,利用原先已经求好的路径去储存答案. #include<bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 5e2 + 7; ve

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

hdu 1207 汉诺塔II (DP+递推)

汉诺塔II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4529    Accepted Submission(s): 2231 Problem Description 经典的汉诺塔问题经常作为一个递归的经典例题存在.可能有人并不知道汉诺塔问题的典故.汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往

[hdu 2102]bfs+注意INF

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2102 感觉这个题非常水,结果一直WA,最后发现居然是0x3f3f3f3f不够大导致的--把INF改成INF+INF就过了. #include<bits/stdc++.h> using namespace std; bool vis[2][15][15]; char s[2][15][15]; const int INF=0x3f3f3f3f; const int fx[]={0,0,1,-1};

HDU 3555 Bomb (数位DP)

数位dp,主要用来解决统计满足某类特殊关系或有某些特点的区间内的数的个数,它是按位来进行计数统计的,可以保存子状态,速度较快.数位dp做多了后,套路基本上都差不多,关键把要保存的状态给抽象出来,保存下来. 简介: 顾名思义,所谓的数位DP就是按照数字的个,十,百,千--位数进行的DP.数位DP的题目有着非常明显的性质: 询问[l,r]的区间内,有多少的数字满足某个性质 做法根据前缀和的思想,求出[0,l-1]和[0,r]中满足性质的数的个数,然后相减即可. 算法核心: 关于数位DP,貌似写法还是

HDU 5917 Instability ramsey定理

http://acm.hdu.edu.cn/showproblem.php?pid=5917 即世界上任意6个人中,总有3个人相互认识,或互相皆不认识. 所以子集 >= 6的一定是合法的. 然后总的子集数目是2^n,减去不合法的,暴力枚举即可. 选了1个肯定不合法,2个也是,3个的话C(n, 3)枚举判断,C(n, 4), C(n, 5) #include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using name

hdu 6166 Senior Pan

地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=6166 题目: Senior Pan Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 245    Accepted Submission(s): 71 Problem Description Senior Pan fails i