做任务(最大闭权子图)

现有一款游戏,你作为玩家,拥有k种物品。开始时,每种物品有1000件。

现在,在你面前有n个任务,每种任务都可能消耗一些物品,也可能得到一些物品。做第i个任务的物品得失情况用一个包含k个字母的字符串Si表示,其中每个字母都是+,-,/中的一种,第j个字母表示该任务对物品j的数量的影响。+表示做这个任务能得到一个物品j,-表示做这个任务会消耗一个物品j,/表示做这个任务对物品j的数量不产生影响。

但是,做任务是有前提条件的。游戏设计者约定了m个限制关系,每个限制关系是一个有序数对(i, j),表示做任务i前必须先做任务j。

现在,你需要选择性的做一些任务,使得获得的物品最多。

比较两种方案的获得的物品数的方法如下:先比较他们获得第物品1的个数,若相同,再比较物品2,若相同,再比较物品3,以此类推。

Input

第一行有三个整数n,m,k

接下来的n行,每行有一个字符串,第i行的字符串表示Si

接下来的m行,每行有两个整数i,j表示限制关系

Output

输出包含一行,k个空格分隔的整数,表示做完你选的任务之后每种物品的拥有量。

样例输入

3 3 2
+-
+/
-+
2 1
2 3
3 1

样例输出

1001 1000

100%的数据,n≤1000, k≤5, m≤5000,保证限制关系不会有环。

思路:最大闭权子图板子。最大闭权子图就是选中当前任务一定要选它的后继节点。在本题中将图反着建就可以了。对于任务获得的价值可以写一个结构体,重载运算符会比较方便。关于最大闭权子图的证明,可以看这篇

#include<bits/stdc++.h>
using namespace std;
const int INF=1000000007;
const int N=1005;
const int M=5005;
int n,m,k,s,t;
struct node{
    int p[6];
}zero,inf;
inline bool operator < (node a,node b)
{
    for(int i=1;i<=k;++i)
        if(a.p[i]^b.p[i])return a.p[i]<b.p[i];
    return false;
}
inline node operator + (node a,node b)
{
    for(int i=1;i<=k;++i)
        a.p[i]+=b.p[i];
    return a;
}
inline node operator - (node a,node b)
{
    for(int i=1;i<=k;++i)
        a.p[i]-=b.p[i];
    return a;
}
inline bool operator !=(node a,node b)
{
    for(int i=1;i<=k;++i)
        if(a.p[i]^b.p[i])return true;
    return false;
}
struct edge{
    int to,nxt;
    node val;
}e[(N+M)<<1];
int num_edge=1,head[N];
void add(int from,int to,node val)
{
    ++num_edge;
    e[num_edge].nxt=head[from];
    e[num_edge].to=to;
    e[num_edge].val=val;
    head[from]=num_edge;
}
bool inq[N];
int dep[N],cur[N];
node maxflow;
bool bfs()
{
    queue<int>q;
    for(int i=1;i<=t;++i)
        dep[i]=INF,cur[i]=head[i],inq[i]=false;
    q.push(s);
    dep[s]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();inq[u]=false;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(dep[v]>dep[u]+1&&e[i].val!=zero)
            {
                dep[v]=dep[u]+1;
                if(!inq[v])
                {
                    inq[v]=true;
                    q.push(v);
                }
            }
        }
    }
    return dep[t]!=INF;
}
node dfs(int u,node flow)
{
    if(u==t)
    {
        maxflow=maxflow+flow;
        return flow;
    }
    node used=zero,rlow;
    for(int i=cur[u];i;i=e[i].nxt)
    {
        int v=e[i].to;cur[u]=i;
        if(e[i].val!=zero&&dep[v]==dep[u]+1)
        {
            rlow=dfs(v,min(flow-used,e[i].val));
            if(rlow!=zero)
            {
                used=used+rlow;
                e[i].val=e[i].val-rlow;
                e[i^1].val=e[i^1].val+rlow;
                if(!(used!=flow))break;
            }
        }
     }
    return used;
}
void dinic()
{
    while(bfs())dfs(s,inf);
}
void print(node a)
{
    for(int i=1;i<=k;++i)
        printf("%d%c",a.p[i],i==k?'\n':' ');
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    char ch[6];node tmp;
    for(int i=1;i<=k;++i)
        zero.p[i]=0,inf.p[i]=INF;
    s=n+1,t=n+2;
    node ans=zero;
    for(int i=1;i<=n;++i)
    {
        scanf("%s",ch+1);
        for(int j=1;j<=k;++j)
        {
            if(ch[j]=='+')tmp.p[j]=1;
            if(ch[j]=='-')tmp.p[j]=-1;
            if(ch[j]=='/')tmp.p[j]=0;
        }
        if(tmp<zero){add(i,t,zero-tmp);add(t,i,zero);}
        else{add(s,i,tmp);add(i,s,zero);ans=ans+tmp;}
    }
    for(int i=1,x,y;i<=m;++i)
    {
        scanf("%d%d",&x,&y);
        add(x,y,inf);add(y,x,zero);
    }
    dinic();
    ans=ans-maxflow;
    for(int i=1;i<=k;++i)
        printf("%d%c",1000+ans.p[i],i==k?'\n':' ');
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zzctommy/p/12317241.html