hdu 3435 A new Graph Game

//邻接表 2859MS
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1010*2;
const int maxm=10010*10;//最大顶点数和边数
const int maxl=999999999;
inline int Min(int a,int b)
{
    return a<b?a:b;
}
inline int Max(int a,int b)
{
    return a>b?a:b;
}
struct st
{
    int y,d;
    int ne;
    int bro;
    int f;
} e[maxm];
int ee;
int st[maxn];
int n,m;
int F;
void addedge(int x,int y,int d,int f)
{
    //给顶点x和y间添加一条费用d,流量f的边
    e[ee].y=y;
    e[ee].d=d;
    e[ee].ne=st[x];
    e[ee].f=f;
    st[x]=ee++;
    e[ee].y=x;
    e[ee].d=-1*d;
    e[ee].ne=st[y];
    e[ee].f=0;
    st[y]=ee++;
    e[ee-2].bro=ee-1;
    e[ee-1].bro=ee-2;
}
int d[maxn],p[maxn];
//spfa所用到起点的最短距离(这里距离相当于cost)和路径记录之前的一个节点
int c[maxn];//spfa所用数组:是否在队列中
int que[maxn],head,tail;//spfa专用队列
int spfa(int sx,int ex)//求sx到ex的一次费用增广
{
    //如果没有增广路就返回maxl 否则返回费用
    int i,j,k;
    for (i=0; i<maxn; i++) d[i]=maxl;
    memset(c,0,sizeof(c));//初始化都没进
    d[sx]=0;
    que[head=0]=sx;
    tail=1;
    c[sx]=1;
    while (head!=tail)
    {
        k=que[head++];
        head%=maxn;
        c[k]=0;
        for (i=st[k]; i!=-1; i=e[i].ne) if (e[i].f)
                if (d[k]+e[i].d<d[e[i].y])
                {
                    d[e[i].y]=d[k]+e[i].d;
                    p[e[i].y]=i;
                    if (c[e[i].y]==0)
                    {
                        c[e[i].y]=1;
                        if (e[i].d<0)
                        {
                            head=(head-1+maxn)%maxn;
                            que[head]=e[i].y;
                        }
                        else
                        {
                            que[tail++]=e[i].y;
                            tail%=maxn;
                        }
                    }
                }
    }
    if (d[ex]==maxl) return maxl;
//如果无法到达终点返回maxl
    k=maxl;
    for (i=ex; i!=sx; i=e[e[p[i]].bro].y)
        k=Min(k,e[p[i]].f); //计算流
    //sum+=k; //sum计算流量
    F+=k;
    for (i=ex; i!=sx; i=e[e[p[i]].bro].y) //增加反向边
    {
        e[p[i]].f-=k;
        e[e[p[i]].bro].f+=k;
    }
    return d[ex]*k;
//返回费用为流大小*路径长度(cost累加)
}
int main()
{
    int T;
    int cas=1;
    int m;
    scanf("%d",&T);
    while(T--)
    {
        int nn,mm;
        scanf("%d%d",&nn,&mm);
        memset(st,-1,sizeof(st));
        ee=0;

        for(int i=1; i<=mm; i++)
        {
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            addedge(x,y+nn,c,1);
            addedge(y,x+nn,c,1);
        }

        for(int i=1; i<=nn; i++)
        {
            addedge(0,i,0,1);
            addedge(i+nn,nn+nn+1,0,1);
        }

        n=nn*2+2;
        F=0;
        int tot=0,k;
        while ((k=spfa(0,n-1))!=maxl) tot+=k;

        //printf("%")
        if(F!=nn)  printf("Case %d: NO\n",cas++);
        else printf("Case %d: %d\n",cas++,tot);
    }
    return 0;
}



//c++ 2390ms
//完美匹配
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=1<<28;
int g[1005][1005],lx[1005],ly[1005];//顶点标号
bool sx[1005],sy[1005];//是否已经搜索过
int link[1005],n,stack[1005];
bool path(int k)
{
    sx[k]=true;
    for(int i=1; i<=n; i++)
    {
        if(sy[i])  continue;
        int t=ly[i]+lx[k]-g[k][i];
        if(t==0)
        {
            sy[i]=1;
            if(link[i]==-1||path(link[i]))
            {
                link[i]=k;
                return true;
            }
        }
        else if(stack[i]>t) stack[i]=t;
    }
    return false;
}
int BestMatch()
{
    int d,sum;
    memset(ly,0,sizeof(ly));
    memset(link,-1,sizeof(link));
    for(int i=1; i<=n; i++)
    {
        lx[i]=-inf;
        for(int j=1; j<=n; j++)
            if(lx[i]<g[i][j]&&g[i][j]!=0)  lx[i]=g[i][j];
    }
    for(int k=1; k<=n; k++)
    {
        for (int i=1; i<=n; i++) stack[i]=inf;
        while(1)
        {
            memset(sx,0,sizeof(sx));
            memset(sy,0,sizeof(sy));
            if(path(k))  break;
            d=inf;
            for(int i=1; i<=n; i++)
                if (!sy[i]&&stack[i]<d) d=stack[i];
            for(int i=1; i<=n; i++)
                if(sx[i]) lx[i]-=d;
            for(int i=1; i<=n; i++)
                if(sy[i]) ly[i]+=d;
                else  stack[i]-=d;
        }
    }
    sum=0;
    for(int i=1; i<=n; i++)
    {
        if(link[i]==-1||g[link[i]][i]==-inf)  return -1;
        sum+=g[link[i]][i];
    }
    return -sum;
}
int main()
{
    int T;
    int cas=1;
    int m;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                g[i][j]=inf;
        for(int i=1; i<=m; i++)
        {
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            g[x][y]=g[y][x]=min(g[x][y],c);
        }
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++) g[i][j]=-g[i][j];

        int t=BestMatch();
        if(t==-1)  printf("Case %d: NO\n",cas++);
        else printf("Case %d: %d\n",cas++,t);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值