HDU5740 Glorious Brilliance

来源:互联网 发布:淘宝店铺音乐代码 编辑:程序博客网 时间:2024/05/21 05:42

题目链接:点击打开链接

题目大意:给一个无向图(1<n<=500),每个点为黑色或者是白色,要求相邻的节点颜色不相同。现在有一种操作,交换两个相邻节点的颜色。问使得图颜色合法的最少操作数,并输出操作序列,如果不可能让图合法则输出-1。


解析:

当一个图有解时,确定任意一个节点的颜色,则其他节点的颜色均能确定,根据距离奇偶判定即可,那么一定有两种染色方案。

下面两种情况是不可能得到合法的染色的:

1.图中存在奇环。

2.错误的黑点个数不等于白点个数。所谓的错误的颜色就是指该位置本应为白(黑)色,实际为黑(白)色。


奇环可以通过一遍dfs判断。

如果两种染色方案的错误黑点个数均不等于错误白点个数,说明不可行,这也可以通过dfs判断。


要交换两个位置的点的颜色,并不产生其他影响,交换的最少操作数为两点在图上的最短路径。首先要交换的两个点颜色一定不相同,从某一点触发,需要和路径上的异色点交换,同色点不需要交换。再从另一端点返回,同样也是与异色点交换。

例如

1234567

0001011

需要将2和7位置互换。

交换序列为:

(3,4)(5,6)(6,7)(5,4)(3,2)

1234567

0101010


最短距离可以bfs得到,寻找点到点长度为k的最短路径可以暴力dfs找。剩下来的问题就是如何对错误的点进行交换,交换代价为最短路径,只需要跑一个带权匹配就可以了。注意,找到一个匹配的时候,需要两个端点染色更新,但不能直接更新到最终的染色中,因为有两种染色方案,所以需要比较两种方案,取更优的更新答案。



因为图可能不连通,所以对于每个连通块做一遍上述操作即可。

细节比较多...


#include <iostream>#include <cstdio>#include <algorithm>#include <vector>#include <cstring>#include <cstdlib>#include <string>#include <cmath>#include <set>#include <map>#include <queue>#include <bitset>using namespace std;typedef long long ll;const int mod = 1000000007;const double eps = 1e-6;const int inf = 0x3f3f3f3f;const ll INF = 100000000000000000ll;const int MAXN = 505;const int MAXM = 310000;namespace MCMF{const static int N = 505;const static int M = 310000;int head[N], pre[N], cur[N], d[N], vis[N], s, e, no;struct point{int u, v, flow, next,cost;point(){};point(int x, int y, int z, int w, int c):u(x), v(y), next(z), flow(w), cost(c){};}p[M];void add(int x, int y, int z, int c){p[no] = point(x, y, head[x], z, c);head[x] = no++;p[no] = point(y, x, head[y], 0, -c);head[y] = no++;}void init(){memset(head, -1, sizeof(head));no = 0;}bool spfa(){    int i, x, y;    queue<int>q;    memset(d, 0x3f, sizeof(d));    memset(vis, false, sizeof(vis));    memset(pre, -1, sizeof(pre));    d[s] = 0;   vis[s] = true;  q.push(s);    while(!q.empty()){        x = q.front();  q.pop();    vis[x] = false;        for(i = head[x]; i != -1; i = p[i].next){            if(p[i].flow && d[y = p[i].v] > d[x] + p[i].cost){                d[y] = d[x] + p[i].cost;   pre[y] = i;                if(vis[y])  continue;                vis[y] = true;  q.push(y);            }  }  }    return d[e] != d[e + 1];}int mcmf(){    int mincost = 0, maxflow = 0, minflow, i;    while(spfa()){        minflow =INF;        for(i = pre[e]; i != -1; i = pre[p[i].u])            minflow = min(minflow, p[i].flow);        for(i = pre[e]; i != -1; i = pre[p[i].u]){            p[i].flow -= minflow;            p[i ^ 1].flow += minflow;        }        mincost += d[e] * minflow; maxflow += minflow;    }    return mincost;}};int n,m;char str[505],ss[2][505];int head[505],wr[505],id[505],dis[505],nn,b,w,tot,qz[505],iqz[505],vis[505],ans[2];//qz是图到网络流图的节点映射,iqz是逆向映射vector<pair<int,int> > temp[2],step;vector<int> seq;struct node{    int v;    int next;    node(int t,int n):v(t),next(n){}    node(){}}edge[MAXM];void init(){    nn = 0;    tot = 0;    memset(head,-1,sizeof(head));    memset(id,-1,sizeof(id));    step.clear();}bool judge(int x,int la){//判断是否有奇环    bool res = true;    id[x] = la;    for(int i = head[x];~i;i = edge[i].next){        int v = edge[i].v;        if(id[v] == -1){            res&=judge(v,la+1);            if(!res) return false;        }        else{            if((la-id[v]+1)%2) return false;        }    }    return res;}void dfs(int s,int c){//找错误的颜色节点    vis[s] = id[s] = 1;    if(str[s]-'0'!= c) {        wr[s] = 1;        if(c){            w++;            iqz[++tot] = s;            qz[s] = tot;        }        else{            b++;            iqz[++tot] = s;            qz[s] = tot;        }    }    for(int i = head[s];~i;i = edge[i].next){         int v = edge[i].v;         if(!vis[v]){            dfs(v,c^1);         }    }}void bfs(int x){//计算最短距离    memset(dis,-1,sizeof(dis));    queue<int> q;    q.push(x);    dis[x] = 0;    while(!q.empty()){        x = q.front();        int d = dis[x];        q.pop();        for(int i = head[x];~i;i = edge[i].next){            int v = edge[i].v;            if(dis[v] == -1){                dis[v] = d+1;                q.push(v);            }        }    }}int findpath(int x,int to,int dep,int dis){//找最短路径    if(dep>dis) return 0;    vis[x] = 1;    int res = 0;    if(x == to&&dep == dis){        res = 1;    }    for(int i = head[x];~i&&!res;i = edge[i].next){        int v = edge[i].v;        if(!vis[v]){            res |= findpath(v,to,dep+1,dis);        }    }    if(res){        seq.push_back(x);    }    vis[x] = 0;    return res;}int main(){    //specialjudge sj;    //sj.judge();    //freopen("1007.in","r",stdin);    //freopen("1007.out","w",stdout);    int T;    int cas = 1;    cin>>T;    while(T--){        init();        //printf("CAS:%d\n",cas++);        scanf("%d%d%s",&n,&m,str+1);        for(int i = 0;i < m;i++){            int x,y;            scanf("%d%d",&x,&y);            edge[nn] = node(y,head[x]);            head[x] = nn++;            edge[nn] = node(x,head[y]);            head[y] = nn++;        }        bool flag = true;        for(int i = 1;i <= n;i++){            if(id[i] == -1){                flag = judge(i,1);                if(!flag) break;            }        }        if(!flag){            printf("-1\n");            continue;        }        memset(id,0,sizeof(id));        flag = true;        int res = 0;        for(int i = 1;i <= n;i++){//枚举所有连通块            if(!id[i]&&flag){                bool flag2 = false;                for(int l = 0;l < 2;l++){                    memset(wr,0,sizeof(wr));                    memset(vis,0,sizeof(vis));                    for(int j = 1;j <= n;j++) ss[l][j] =  str[j];                    temp[l].clear();                    b = 0;                    w = 0;                    tot = 0;                    ans[l] = inf;                    dfs(i,l);                    if(w != b) {                        continue;                    }                    else{                        flag2 = true;                    }                    MCMF::init();                    MCMF::s = 0;                    MCMF::e = tot+1;                    for(int j = 1;j <= n;j++){//网络流建图                        if(id[j]&&wr[j]&&str[j]-'0'==1){                            MCMF::add(MCMF::s,qz[j],1,0);                        }                        if(id[j]&&wr[j]&&str[j]-'0'==0){                            MCMF::add(qz[j],MCMF::e,1,0);                        }                    }                    for(int j = 1;j <= n;j++){                        if(id[j]&&wr[j]&&str[j]-'0'==1){                            bfs(j);                            for(int k = 1;k <= n;k++){                                if(id[k]&&wr[k]&&str[k]-'0'==0){                                    MCMF::add(qz[j],qz[k],1,dis[k]);                                }                            }                        }                    }                    ans[l] = MCMF::mcmf();                    for(int j = 1;j <= tot;j++){                        int cc = iqz[j];                        if(str[cc]-'0' == 0){//if it connect to end                            for(int k = MCMF::head[j];~k;k = MCMF::p[k].next){                                if(MCMF::p[k].v != MCMF::e && MCMF::p[k].flow == 1){                                    for(int o = 0;o < 505;o++) vis[o] = 0;                                    seq.clear();                                    int from,to,dis;                                    from = iqz[MCMF::p[k].v];                                    to = iqz[j];                                    dis = -MCMF::p[k].cost;                                    findpath(from,to,0,dis);                                    int c = ss[l][seq[0]]-'0',pos = 0;                                    for(int o = 0;o < 505;o++) vis[o] = 0;                                    for(int o = 1;o < seq.size();o++){//输出操作                                         int tc = ss[l][seq[o]]-'0';                                         if(c^tc){                                            vis[o] = 1;                                            int a = seq[pos],b = seq[o];                                            temp[l].push_back(pair<int,int>(a,b));                                            swap(ss[l][a],ss[l][b]);                                         }                                         pos = o;                                    }                                    for(int o = seq.size()-1;o > 0;o--){//输出操作                                        if(!vis[o]){                                            int a = seq[o],b = seq[o-1];                                            temp[l].push_back(pair<int,int>(a,b));                                            swap(ss[l][a],ss[l][b]);                                        }                                    }                                }                            }                        }                    }                }                if(!flag2){                    flag = false;                    break;                }                int op;                if(ans[0]<ans[1]){                    op = 0;                }                else op = 1;                res += ans[op];                for(int j = 0;j < temp[op].size();j++){                    step.push_back(temp[op][j]);                }                for(int j = 1;j <= n;j++) str[j] = ss[op][j];//更新状态            }        }        if(!flag){            printf("-1\n");            continue;        }        printf("%d\n",res);        for(int i = 0;i < step.size();i++){            printf("%d %d\n",step[i].first,step[i].second);        }    }    return 0;}


0 0