CF 21D Traveling Graph

来源:互联网 发布:校园安全事件网络诈骗 编辑:程序博客网 时间:2024/05/21 10:55

CF 21D Traveling Graph

题目大意:一张无向图有n个点(n15),m条边(m2000),存在重边和自环,求最小的回路从1出发能够通过所有的边至少一次。

题解:
如果这张图是一张欧拉图的话,那么存在一条欧拉回路通过所有的边一次,一定是最小的回路。如果不是欧拉图的话,那么可以通过补一些边使得它成为一张欧拉图。首先floyd处理出两点之间的最短距离,然后在奇数度顶点之间加边,将所有的顶点补为偶数度。实际上是求所有的奇数度顶点的一个最小权完美匹配,可以枚举二分图费用流解。那么最终的解就是所有边权和加上最小的费用流费用。

#include <bits/stdc++.h>using namespace std;const int MAXN = 25;const int MAXE = 10000;const int INF = 0x3f3f3f3f;class MCMF{public:struct Edge {    int u,v,f,cost,next;    Edge() {};    Edge(int u,int v,int f,int cost,int next):u(u),v(v),f(f),cost(cost),next(next) {};};Edge edge[MAXE];int n,k,head[MAXN],dis[MAXN],pe[MAXN],nEdge;bool vis[MAXN];void init() {    memset(head,-1,sizeof(head));    nEdge=0;}void addedge(int u,int v,int c,int cost) {    edge[nEdge]=Edge(u,v,c,cost,head[u]);    head[u]=nEdge++;    edge[nEdge]=Edge(v,u,0,-cost,head[v]);    head[v]=nEdge++;}bool spfa(int src,int sink) {    memset(vis,false,sizeof(vis));    memset(dis,0x3f3f3f3f,sizeof(dis));    memset(pe,-1,sizeof(pe));    queue<int> q;    q.push(src);    dis[src]=0;    vis[src]=true;    while(!q.empty()) {        int u=q.front();        q.pop();        vis[u]=false;        for(int i=head[u];i!=-1;i=edge[i].next) {            int f=edge[i].f,v=edge[i].v,cost=edge[i].cost;            if(f&&dis[u]+cost<dis[v]) {                dis[v]=dis[u]+cost;                pe[v]=i;                if(!vis[v]) {                    vis[v]=true;                    q.push(v);                }            }        }    }    return dis[sink]<INF;}int min_cost_max_flow(int src,int sink) {    int ans=0;    while(spfa(src,sink)) {        int delta=INF;        for(int i=pe[sink];i!=-1;i=pe[edge[i].u]) delta=min(delta,edge[i].f);        for(int i=pe[sink];i!=-1;i=pe[edge[i].u]){            edge[i].f-=delta;            edge[i^1].f+=delta;        }ans+=dis[sink]*delta;    }    return ans;}}mcmf;struct node{    int v,val;    int next;    node(int v,int val,int next):v(v),val(val),next(next){}    node(){}}edge[MAXE];int head[MAXN],deg[MAXN],vis[MAXE],nn;void dfs(int u){    for(int i = head[u];~i;i= edge[i].next){        int v = edge[i].v;        if(vis[i]||vis[i^1]) continue;        vis[i] = 1;        vis[i^1] = 1;        dfs(v);    }}void addedge(int u,int v,int w){    edge[nn] = node(v,w,head[u]);    head[u] = nn++;}int dis[MAXN][MAXN];vector<int> V;void init(){    nn = 0;    memset(head,-1,sizeof(head));    memset(deg,0,sizeof(deg));    memset(vis,0,sizeof(vis));    memset(dis,0x3f,sizeof(dis));}int main(){    int n,m,u,v,w;    while(~scanf("%d%d",&n,&m)){        init();        V.clear();        int ans = 0;        for(int i = 0;i < m;i++){            scanf("%d%d%d",&u,&v,&w);            dis[u][v] = min(dis[u][v],w);            dis[v][u] = dis[u][v];            ans += w;            addedge(u,v,w);            addedge(v,u,w);            deg[u]++;            deg[v]++;        }        dfs(1);        int flag = 0;        for(int i = 1;i <= n;i++) if(deg[i]%2) V.push_back(i);        for(int i = 0;i < nn;i++) if(!vis[i]){ flag = 1; break; }        if(flag){            puts("-1");            continue;        }        for(int k = 1;k <= n;k++)            for(int i = 1;i <= n;i++)                for(int j = 1;j <= n;j++)                    dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);        int kk = V.size();        int tmp = 0;        if(kk){            tmp = INF;            for(int i = 1;i < 1<<kk;i++){                int t,cnt = 0;                t = i;                while(t){                    if(t&1) cnt++;                    t>>=1;                }                if(cnt == kk/2){                    mcmf.init();                    for(int j = 0;j < kk;j++){                        if((i>>j)&1){                            mcmf.addedge(0,j+1,1,0);                            for(int k = 0;k < kk;k++){                                if(!((i>>k)&1)){                                    mcmf.addedge(j+1,k+1,1,dis[V[j]][V[k]]);                                }                            }                        }                        else{                            mcmf.addedge(j+1,kk+1,1,0);                        }                    }                    tmp = min(tmp,mcmf.min_cost_max_flow(0,kk+1));                }            }        }        printf("%d\n",ans+tmp);    }    return 0;}
0 0
原创粉丝点击