您的位置:首页 > 其它

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

2014-05-07 13:47 459 查看
题意:选一条路线,使得经过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
,ly
,link
,slack
,visx
,visy
,w

;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: