现有一款游戏,你作为玩家,拥有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;
}