CF 21D Traveling Graph

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章