HDU 3488 Tour 最小費用最大流||最大匹配


題意:選一條路線,使得經過n條路,並且有環,回到起點

分析:n條路分別從n個不同的點出發,到達不同的點,用最大匹配可解

把每個點拆成2個,一個進,一個出,連接源點跟所有進入點,容量爲1,費用爲0,連接所以出點和匯點,容量爲1,費用爲0

對於每條邊(u,v,w),連接u,v+n,容量爲1,費用爲w;


費用流

#include <iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
#define MAXN 405
#define MAXE 60805
using namespace std;
int net[MAXN],size;
struct Edge{
    int v,next,cap,cost;
}edge[MAXE];
void init(){
    size=0;
    memset(net,-1,sizeof(net));
}
void addedge(int u,int v,int cap,int cost){
    //cout<<'*'<<u<<' '<<v<<' '<<cost<<endl;
    edge[size].v=v;edge[size].cap=cap;edge[size].cost=cost;edge[size].next=net[u];net[u]=size++;
    edge[size].v=u;edge[size].cap=0;edge[size].cost=-cost;edge[size].next=net[v];net[v]=size++;
}
int nv,dist[MAXN],pre[MAXN],pe[MAXN];
bool hash[MAXN];
queue<int> q;
bool spfa(int s,int t){
    while(!q.empty())
    q.pop();
    memset(hash,0,sizeof(hash));
    memset(pre,-1,sizeof(pre));
    for(int i=1;i<=nv;i++)
        dist[i]=INF;
    dist[s]=0;
    hash[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        hash[u]=0;
        for(int i=net[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&dist[v]>dist[u]+edge[i].cost){
                dist[v]=dist[u]+edge[i].cost;
                pre[v]=u;
                pe[v]=i;
                if(hash[v]==0){
                    hash[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(pre[t]==-1)
    return false;
    return true;
}
int MCMF(int s,int t,int need=0){
    int max_flow=0;
    int min_cost=0;
    while(spfa(s,t)){
        int aug=INF;
        for(int v=t;v!=s;v=pre[v]){
            aug=min(aug,edge[pe[v]].cap);
        }
        max_flow+=aug;
        min_cost+=dist[t]*aug;
        for(int v=t;v!=s;v=pre[v]){
            edge[pe[v]].cap-=aug;
            edge[pe[v]^1].cap+=aug;
        }
    }
    if(max_flow<need)
    return -1;
    return min_cost;
}
int main()
{
    int T,s,t,u,v,w,i,ans,n,m;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d%d",&n,&m);
        while(m--){
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v+n,1,w);
        }
        s=0;
        t=n*2+1;
        for(i=1;i<=n;i++){
            addedge(s,i,1,0);
            addedge(i+n,t,1,0);
        }
        nv=t+1;
        ans=MCMF(s,t,0);
        printf("%d\n",ans);
    }
    return 0;
}



將值取反,求最大匹配,注意INF不能過大

#include <iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cstring>
#include<queue>
#define INF 60001
#define N 205
using namespace std;
int nx,ny,lx[N],ly[N],link[N],slack[N],visx[N],visy[N],w[N][N];
bool DFS(int x){
    int y;
    visx[x]=1;
    for(y=1;y<=ny;y++){
        if(!visy[y]){
            int t=lx[x]+ly[y]-w[x][y];
            if(t==0){
                visy[y]=1;
                if(link[y]==-1||DFS(link[y])){
                    link[y]=x;
                    return true;
                }
            }else if(slack[y]>t){
                slack[y]=t;
            }
        }
    }
    return false;
}
int KM(){
    int i,j,x;
    memset(link,-1,sizeof(link));
    memset(ly,0,sizeof(ly));
    for(i=1;i<=nx;i++){
        for(j=1,lx[i]=-INF;j<=ny;j++)
        if(w[i][j]>lx[i])
        lx[i]=w[i][j];
    }
    for(x=1;x<=nx;x++){
        for(i=1;i<=ny;i++)
        slack[i]=INF;
        while(1){
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(DFS(x))
            break;
            int d=INF;
            for(i=1;i<=ny;i++)
                if(!visy[i]&&d>slack[i])
                d=slack[i];
            for(i=1;i<=nx;i++)
                if(visx[i])
                lx[i]-=d;
            for(i=1;i<=ny;i++){
                if(visy[i])
                ly[i]+=d;
                else
                slack[i]-=d;
            }
        }
    }
    int ans=0;
    for(i=1;i<=ny;i++)
        if(link[i]>-1)
        ans+=w[link[i]][i];
    return ans;
}
int main()
{
    int T,s,t,i,j,k,ans,n,m;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        nx=ny=n;
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++)
            w[i][j]=-INF;
        }
        while(m--){
            scanf("%d%d%d",&i,&j,&k);
            w[i][j]=max(w[i][j],-k);
        }
        ans=KM();
        printf("%d\n",-ans);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章