hdu A new Graph Game (最小权匹配/费用流)

题意:  给个无向图,有重边(取最小权值即可),有n个点,要求每个点在一个环中,球最小的总权值。 因为是无向图,所有要见两条;

 

KM_match():

/*HDU 1853*/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
using namespace std;

const int maxn = 1010;
const int INF = 1<<30;

int n, m;
int g[maxn][maxn];
int Lx[maxn], Ly[maxn];
int match[maxn];
bool fx[maxn], fy[maxn];

bool dfs(int i)
{
    fx[i] = 1;
    for(int j = 1; j <= n; j++) 
	if(Lx[i]+Ly[j] == g[i][j] && !fy[j])
    {
        fy[j] = 1;
        if(match[j]==-1 ||dfs(match[j]))
        {
            match[j] = i;
            return 1;
        }
    }
    return 0;
}

int KM_match()
{
    memset(match, -1, sizeof(match));
    memset(Ly, 0, sizeof(Ly)); 
    for(int i = 1; i <= n; i++)
    {
    	Lx[i]=-INF ;
        for(int j = 1; j <= n; j++)
            Lx[i] = max(Lx[i], g[i][j]);
    }
    for(int k = 1; k <= n; k++)
    {
        while(1)
        {
             memset(fx,0,sizeof(fx));
             memset(fy,0,sizeof(fy));
            if(dfs(k)) break; 
            int a = INF;
         for(int i = 1; i <= n; i++) 
		    if(fx[i])
                for(int j = 1; j <= n; j++) 
				   if(!fy[j])
                    a = min(a, Lx[i]+Ly[j]-g[i][j]);
        
          for(int i = 1; i <= n; i++)      if(fx[i]) Lx[i] -= a; 
          for(int j = 1; j <= n; j++)      if(fy[j]) Ly[j] += a;
        } 
    }
    int ans = 0;
	
    int sum=0;
    for(int i = 1 ; i <= n ;i++)
      {  
          if(match[i]==-1 || g[match[i]][i]==-INF) return -1 ;  //没有最有匹配(完备匹配) 
          sum += g[match[i]][i] ;
     }
     return -sum ;
}


int main()
{
	int t,u,v,w;
    scanf("%d",&t);
    for(int k = 1 ; k <= t ; k++) 
    {
             scanf("%d%d",&n,&m);
             for(int i = 1 ; i <= n ;i++)
                 for(int j = 1 ; j <= n ;j++)
                     g[i][j] = -INF ;
             while(m--)
             {
                   scanf("%d%d%d",&u,&v,&w);
                   if(g[u][v] < -w)
                      g[u][v] =g[v][u]= -w ;     //注意无向边 
             }
             int ans=KM_match();
             if(ans==-1 )  printf("Case %d: NO\n",k);
             else printf("Case %d: %d\n",k,ans);
    }
    return 0;
}

 

最小费用最大流:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define inf 99999999
using namespace std;
struct node
{
    int u,v,f,c;
};
node e[60000];
int first[3000],next[60000],cc;
int p[3000],preedge[3000],d[3000],ans_flow,ans_cost;
inline void add_edge(int u,int v,int f,int c)
{
    e[cc].u=u;
    e[cc].v=v;
    e[cc].f=f;
    e[cc].c=c;
    next[cc]=first[u];
    first[u]=cc;
    cc++;

    e[cc].v=u;
    e[cc].u=v;
    e[cc].f=0;
    e[cc].c=-c;
    next[cc]=first[v];
    first[v]=cc;
    cc++;
}
bool spfa(int s,int t)
{
    int inq[3000];
    memset(inq,0,sizeof(inq));
    memset(p,-1,sizeof(p));
    memset(preedge,-1,sizeof(preedge));
    int i;
    for(i=0;i<=t;i++)
        d[i]=inf;
    d[s]=0;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        inq[u]=0;
        for(i=first[u];i!=-1;i=next[i])
        {
            if(e[i].f)
            {
                int v=e[i].v;
                if(d[v]>d[u]+e[i].c)
                {
                    d[v]=d[u]+e[i].c;
                    p[v]=u;
                    preedge[v]=i;
                    if(!inq[v])
                    {
                        inq[v]=1;
                        q.push(v);
                    }
                }
            }
        }
    }
    if(d[t]>=inf)
        return false;
    else
        return true;
}
void min_cost_flow(int s,int t)
{
    ans_cost=0;ans_flow=0;
    while(spfa(s,t))
    {
        int u=t;
        int mm=inf;
        while(p[u]!=-1)
        {
            mm=min(mm,e[preedge[u]].f);
            u=p[u];
        }
        u=t;
        while(p[u]!=-1)
        {
            e[preedge[u]].f-=mm;
            e[preedge[u]^1].f+=mm;
            u=p[u];
        }
        ans_cost+=mm*d[t];
        ans_flow+=mm;
    }
}
int main()
{
    int tt;
    scanf("%d",&tt);
    int cas;
    for(cas=1;cas<=tt;cas++)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        int i;
        int s=0;
        int t=2*n+1;
        memset(first,-1,sizeof(first));
        memset(next,-1,sizeof(next));
        cc=0;
        for(i=1;i<=n;i++)
        {
            add_edge(s,i,1,0);
            add_edge(n+i,t,1,0);
        }
        for(i=0;i<m;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v+n,1,w);
            add_edge(v,u+n,1,w);
        }
        min_cost_flow(s,t);
        if(ans_flow<n)
            printf("Case %d: NO\n",cas);
        else
            printf("Case %d: %d\n",cas,ans_cost);
    }
    return 0;
}



 

你可能感兴趣的:(hdu A new Graph Game (最小权匹配/费用流))