hdu 3395 Special Fish【最大费用流】

本文介绍了一个关于特殊鱼类的问题,通过构建一个复杂的图模型,并运用最大费用流算法来解决该问题,旨在找到所有可能配对中价值最大的组合。

Special Fish

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2215    Accepted Submission(s): 833

Problem Description

There is a kind of special fish in the East Lake where is closed to campus of Wuhan University. It’s hard to say which gender of those fish are, because every fish believes itself as a male, and it may attack one of some other fish who is believed to be female by it.
A fish will spawn after it has been attacked. Each fish can attack one other fish and can only be attacked once. No matter a fish is attacked or not, it can still try to attack another fish which is believed to be female by it.
There is a value we assigned to each fish and the spawns that two fish spawned also have a value which can be calculated by XOR operator through the value of its parents.
We want to know the maximum possibility of the sum of the spawns.

Input

The input consists of multiply test cases. The first line of each test case contains an integer n (0 < n <= 100), which is the number of the fish. The next line consists of n integers, indicating the value (0 < value <= 100) of each fish. The next n lines, each line contains n integers, represent a 01 matrix. The i-th fish believes the j-th fish is female if and only if the value in row i and column j if 1.
The last test case is followed by a zero, which means the end of the input.

Output

Output the value for each test in a single line.

Sample Input

3

1 2 3

011

101

110

0

Sample Output

6

Author

momodi@whu

Source

The 5th Guangting Cup Central China Invitational Programming Contest


题目大意:


有n条鱼,每条鱼都有一个权值,然后给出一个n*n的一个邻接矩阵,如果map【i】【j】==1表示i可以攻击J,其能够获得的价值是val【i】^ val【j】;每一条鱼只能攻击一次,也只能被攻击一次,问最大获得价值。


思路:


1、首先,对于建图:

①建立超级源点,将源点连入每一条鱼(1-n),其权值设定为1,费用设定为0,表示每一条鱼只能攻击出去一次。

②建立超级汇点,将每条鱼的拆点(n+1-2n)连入汇点,其权值设定为1,费用设定为0,表示每一条鱼只能被攻击一次。

③将每一条鱼(1-n)连入其拆点(n+1-2n)【当然要求是能够攻击的鱼】,其权值设定为1,费用设定为val【i】^val【j】。表示某条鱼攻击出去之后,会获得的价值。


2、然后注意这个题不需要最大流时候的最大费用,而是求一个最大费用,无论在什么流时候都行,那么我们跑最长路过后,如果发现这条最长路是负权值的时候,那么就要直接退出。(因为退回边的作用,会在跑最长路的时候出现负权值)。


Ac代码:


#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
#define INF 0x3f3f3f3f
struct node
{
    int from;
    int to;
    int next;
    int w;
    int f;
    int num;
}e[100*100*5];
int vis[2050];
int pre[2050];
int path[2050];
int dis[2050];
int head[2050];
char a[150][150];
int val[2050];
int n,cont,ss,tt;
void add(int from,int to,int w,int f)
{
    e[cont].to=to;
    e[cont].f=f;
    e[cont].w=w;
    e[cont].num=cont;
    e[cont].next=head[from];
    head[from]=cont++;
}
void getmap()
{
    ss=2*n+1;
    tt=ss+1;
    cont=0;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
    {
        add(ss,i,0,1);
        add(i,ss,0,0);
        add(i+n,tt,0,1);
        add(tt,i+n,0,0);
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(a[i][j]=='1')
            {
                int u=i+1;
                int v=j+1+n;
                add(u,v,val[i+1]^val[j+1],1);
                add(v,u,-(val[i+1]^val[j+1]),0);
            }
        }
    }
}
int SPFA()
{
    queue<int >s;
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    memset(path,-1,sizeof(path));
    for(int i=0;i<=tt;i++)dis[i]=-0x3f3f3f3f;
    vis[ss]=1;
    dis[ss]=0;
    s.push(ss);
    while(!s.empty())
    {
        int u=s.front();
        s.pop();vis[u]=0;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            int w=e[i].w;
            int f=e[i].f;
            if(f>0&&dis[v]<dis[u]+w)
            {
                dis[v]=dis[u]+w;
                pre[v]=u;
                path[v]=e[i].num;
                if(vis[v]==0)
                {
                    vis[v]=1;
                    s.push(v);
                }
            }
        }
    }
    if(dis[tt]!=0x3f3f3f3f)return 1;
    else return 0;
}
void Maxcost_Maxflow()
{
    int ans=0;
    int maxflow=0;
    while(SPFA()==1)
    {
        if(dis[tt]<0)break;
        int minn=INF;
        for(int i=tt;i!=ss;i=pre[i])
        {
            minn=min(minn,e[path[i]].f);
        }
        for(int i=tt;i!=ss;i=pre[i])
        {
            e[path[i]].f-=minn;
            e[path[i]^1].f+=minn;
        }
        ans+=dis[tt];
        maxflow+=minn*dis[tt];
    }
    printf("%d\n",ans);
}
int main()
{
    while(~scanf("%d",&n))
    {
        if(n==0)break;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&val[i]);
        }
        for(int i=0;i<n;i++)
        {
            scanf("%s",a[i]);
        }
        getmap();
        Maxcost_Maxflow();
    }
    return 0;
}





评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值