【网络流】poj3436

最近难得1A的题目

虽然也是道蛮水的网络流,大概这个题的难度在于读题吧。。。我看了一大堆博文才弄清楚这个题的意思

题目意思大概是这样的,给你n个机器,每个机器有一个使用次数,然后有一个进参数和一个出参数,出参数与进参数匹配就可以连边,然后要使最多的全零状态变为1状态

Sample input 1
3 4
15  0 0 0  0 1 0
10  0 0 0  0 1 1
30  0 1 2  1 1 1
3   0 2 1  1 1 1

用sample来解释,现在的总状态参数是3(p=3);

一开始的状态是(0,0,0);

然后我可以通过第一个machine使状态从(0,0,0)变为(0,1,0),然后再通过第2个machine使状态从(0,1,0)变为(1,1,1,);这样最多可以变化15次因为有15个machine1;

这样的话算法就很明显了,建一个源点一个汇点,源点向所有入点为(0,0,0,0,0,,,,0)(ps:也可以有2),连一条无穷大的边,然后所有出点为(1,1,1,1,1.1...1)的向出点连无穷大的

边。然后不同机器如果出点入点相匹配的话从出点向入点连边。然后每一个机器的入点向出点连一条容量大小的边,这样做最大流就可以了。

因为是special judge所以输出也是比较随意。。。判断一下不同机器之间连的边与初始值的差。




说些题外话,最近虽然是进了acm队但是还是明显觉得实力差的非常多,接下来也打算按照翁队的教诲,认真把每一种类型的题目都刷通。也希望有志于打acm的coder于蒟蒻相互交流拉。。。。留个邮箱prospace@126.com~


最后把这个题代码粘了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
int p,q,n,st,ed,tot=0,link[2010],h[2010],sum[2010];
int s[61][3][21];
struct rec
{
    int num,dis,w,next;
}e[500100];
void insert(int x,int y,int w){
    tot++;e[tot].num=y;e[tot].w=w;e[tot].next=link[x];e[tot].dis=tot+1;link[x]=tot;
    tot++;e[tot].num=x;e[tot].w=0;e[tot].next=link[y];e[tot].dis=tot-1;link[y]=tot;
}
void Input()
{//读入,建自边;建源点,汇点边 ; 
    int tmp_tot;
    scanf("%d%d",&p,&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&q);
        insert(i,n+i,q);
        tmp_tot=0;
        for (int j=1;j<=p;j++)
        {
            scanf("%d",&s[i][1][j]);
            if (s[i][1][j]==1) tmp_tot++;
        }    
        if (tmp_tot==0) insert(2*n+1,i,2000000);
        tmp_tot=0;
        for (int j=1;j<=p;j++)
        {
            scanf("%d",&s[i][2][j]);
            if (s[i][2][j]==0) tmp_tot++;
        }
        if (tmp_tot==0) insert(i+n,2*n+2,2000000);
    }
}

void clear()//初始化 
{
    memset(s,0,sizeof(s));
    memset(e,0,sizeof(e));
    memset(link,0,sizeof(link));
    memset(h,0,sizeof(h));
    memset(sum,0,sizeof(sum));
    tot=0;
}

void make_net()//连相互之间的边,出入点互相连 
{
    bool flag;
    for (int i=1;i<=n;i++)
        for (int j=i+1;j<=n;j++)
        {
            flag=true;
            for (int k=1;k<=p;k++)//s[i]的出到s[j]的入; 
                if ((s[i][2][k]==0&&s[j][1][k]==1)||(s[i][2][k]==1&&s[j][1][k]==0)) 
                {
                    flag=false;
                    break;
                }
            if (flag==true) insert(i+n,j,2000000);
            flag=true;
            for (int k=1;k<=p;k++)//s[j]的出到s[i]的入; 
                if ((s[i][1][k]==0&&s[j][2][k]==1)||(s[i][1][k]==1&&s[j][2][k]==0))
                {
                    flag=false;
                    break;
                }
            if (flag==true) insert(j+n,i,2000000);
            flag=true;
        }
}
int dfs(int x,int total)
{
    if (x==ed) return total;
    int minh=2*n+1,leave=total,w;
    for (int p=link[x];p;p=e[p].next)
    {
        //printf("%d %d %d %d\n",x,total,p,e[p].num);
        if (e[p].w>0)
        {
            if (h[x]==h[e[p].num]+1)
            {
                w=dfs(e[p].num,min(e[p].w,leave));
                e[p].w-=w;
                e[e[p].dis].w+=w;
                leave-=w;
                if (h[st]==ed) return total-leave;
            }
            minh=min(h[e[p].num],minh);
        }
    }
    if (leave==total)
    {
        sum[h[x]]--;
        if (sum[h[x]]==0)
            h[st]=ed;
        h[x]=minh+1;
        sum[h[x]]++; 
    }
    return total-leave;
}
void net_work()
{
    int ans=0;
    while (h[st]<2*n+2)
    {
        ans+=dfs(st,2000000);
        /*for (int ii=1;ii<=10;ii++) 
        {
            printf("%d ",h[ii]);
        }
        printf("\n"); 
        for (int ii=1;ii<=10;ii++) 
        {
            printf("%d ",s[ii]);
        }
        printf("\n");*/
    }
    printf("%d",ans);
}
int main()
{
    clear();
    Input();
    make_net();
    st=2*n+1;
    ed=st+1;
    sum[0]=2*n+2;
    net_work();
    int tmp_ans=0;
    for (int i=1;i<=n;i++)
        for (int p=link[i+n];p;p=e[p].next)
            if (e[p].num!=i&&e[p].num!=2*n+2&&e[p].num!=2*n+1&&e[p].w!=2000000)
                tmp_ans++;
    printf(" %d\n",tmp_ans);
    for (int i=1;i<=n;i++)
        for (int p=link[i+n];p;p=e[p].next)
            if (e[p].num!=i&&e[p].num!=st&&e[p].num!=ed&&e[p].w!=2000000)
                printf("%d %d %d\n",i,e[p].num,2000000-e[p].w);
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值