HDU 3488 Tour [裂点+KM或最小费用最大流]

来源:互联网 发布:淘宝刷单被降权怎么办 编辑:程序博客网 时间:2024/05/21 10:48

题意:有若干地点和若干通道,确定几条回路,要求可到所有点,且仅经过一次,即每个点必须属于且仅能属于一个圈。

思路:

(1)转化为二分图,由题意知,每个点的出度=入度=1,将点裂开,将裂开的点分至两端,用KM以最佳二分图处理;

(2)转化为最大流,同样将点裂开,裂开形成的两点分别控制入度和出度,且流量为1,拟定源点和汇点,源点通往每个入度点,每个出度点通往汇点,以最大流处理。

//(1)#include <stdio.h>#include <string.h>#include <stdlib.h>#include <iostream>using namespace std;#define MAX 202int N;const int inf=10000000;bool x[MAX],y[MAX];int map[MAX][MAX];int my[MAX];int lx[MAX],ly[MAX];int slack[MAX];bool dfs(int t){    int u;    x[t]=1;    for(u=1;u<=N;u++){        int wt=lx[t]+ly[u]-map[t][u];        if(!y[u]&&wt==0){            y[u]=1;            if(my[u]==-1||dfs(my[u])){                my[u]=t;                return 1;            }        }     else if(slack[u]>wt) slack[u]=wt;   }   return 0;}int KM(){    int i,j,k;    for(i=1;i<=N;i++){        my[i]=-1;        lx[i]=-inf,ly[i]=0;        for(j=1;j<=N;j++){            if(lx[i]<map[i][j]) lx[i]=map[i][j];         }     }    for(k=1;k<=N;k++){        memset(x,0,sizeof(x));        memset(y,0,sizeof(y));        for(i=1;i<=N;i++) slack[i]=inf;        while(!dfs(k)){            int d=inf;            for(i=1;i<=N;i++){                if(!y[i]&&slack[i]<d){d=slack[i];}            }            for(i=1;i<=N;i++){                if(x[i]){                    lx[i]=lx[i]-d;                    x[i]=0;                }                if(y[i]){                    ly[i]=ly[i]+d;                    y[i]=0;                }             }         }     }     int ans=0;     for(i=1;i<=N;i++)         ans+=(lx[i]+ly[i]);     return ans;}int main(){    int t,M,a,b,c;    cin>>t;    while(t--){        scanf("%d%d",&N,&M);        for(int i=1;i<=N;i++)            for(int j=1;j<=N;j++)                map[i][j]=-inf;        while(M--){            cin>>a>>b>>c;            map[a][b]=max(map[a][b],-c);        }        cout<<-KM()<<endl;    }    return 0;}//(2)#include <iostream>#include <algorithm>#include <cstdio>#include <queue>#include<memory.h>using namespace std;const int sz = 75000;const int INF = 200000000;struct Edge{int v,w,capacity;int next;}adj[sz * 8];int head[sz],pre[sz],dist[sz],road[sz],src,dest,k;bool inq[sz];void init(const int &n){src = 1;dest = n;k = 0;fill(head,head+dest+1,-1);}void add(const int &v1,const int &v2,const int &w,const int &capacity) {adj[k].v = v2;adj[k].w = w;adj[k].capacity = capacity;adj[k].next = head[v1];head[v1] = k ++;}void addEdge(const int &v1,const int &v2,const int &w,const int &capacity){add(v1,v2,w,capacity);add(v2,v1,-w,0);}bool SPFA(){fill(dist,dist+dest+1,INF);fill(inq,inq+dest+1,false);inq[src] = true;dist[src] = 0;queue < int > q;q.push(src);while(!q.empty()){int t = q.front();q.pop();inq[t] = false;int index = head[t];while(index != -1){if(adj[index].capacity > 0 && dist[t] + adj[index].w < dist[adj[index].v]){dist[adj[index].v] = dist[t] + adj[index].w;pre[adj[index].v] = t;road[adj[index].v] = index;if(!inq[adj[index].v]){q.push(adj[index].v);inq[adj[index].v] = true;}}index = adj[index].next;}}return (dist[dest] != INF);}int minCostMaxFlow(){int minCost = 0,t,nowCost;while(SPFA()){int flow = INF;for(t = dest ; t != src ; t = pre[t] ){if(adj[road[t]].capacity < flow)flow = adj[road[t]].capacity;}nowCost=0;for(t = dest ; t != src ; t = pre[t] ){adj[road[t]].capacity -= flow;//positive edge capacity -= flowadj[road[t]^1].capacity += flow;//nagative edge capacity += flownowCost += flow * adj[road[t]].w;}//if (nowCost<0) ///////////minCost+=nowCost;}return minCost;}int main(){int n;////////!!!!!int i,j,k;int cass;cin>>cass;while(cass--){    int nn,mm;    cin>>nn>>mm;    n=nn*2+2;    init(n);    while(mm--){        scanf("%d%d%d",&i,&j,&k);            addEdge(i+1,j+nn+1,k,1);    }    for (i=1;i<=nn;i++){            addEdge(1,i+1,0,1);            addEdge(i+nn+1,nn+nn+2,0,1);        }        printf("%d\n",minCostMaxFlow());    }return 0;}/*测试:Sample Input16 91 2 52 3 53 1 103 4 124 1 84 6 115 4 75 6 96 5 4Sample Output42*/


 

原创粉丝点击