Time Limit: 1000MS | Memory Limit: 65536K | |||
Total Submissions: 2259 | Accepted: 744 | Special Judge |
Description
As you know, all the computers used for ACM contests must be identical, so the participants compete on equal terms. That is why all these computers are historically produced at the same factory.
Every ACM computer consists of P parts. When all these parts are present, the computer is ready and can be shipped to one of the numerous ACM contests.
Computer manufacturing is fully automated by using N various machines. Each machine removes some parts from a half-finished computer and adds some new parts (removing of parts is sometimes necessary as the parts cannot be added to a computer in arbitrary order). Each machine is described by its performance (measured in computers per hour), input and output specification.
Input specification describes which parts must be present in a half-finished computer for the machine to be able to operate on it. The specification is a set of P numbers 0, 1 or 2 (one number for each part), where 0 means that corresponding part must not be present, 1 — the part is required, 2 — presence of the part doesn't matter.
Output specification describes the result of the operation, and is a set of P numbers 0 or 1, where 0 means that the part is absent, 1 — the part is present.
The machines are connected by very fast production lines so that delivery time is negligibly small compared to production time.
After many years of operation the overall performance of the ACM Computer Factory became insufficient for satisfying the growing contest needs. That is why ACM directorate decided to upgrade the factory.
As different machines were installed in different time periods, they were often not optimally connected to the existing factory machines. It was noted that the easiest way to upgrade the factory is to rearrange production lines. ACM directorate decided to entrust you with solving this problem.
Input
Input file contains integers P N, then N descriptions of the machines. The description of ith machine is represented as by 2 P + 1 integers Qi Si,1 Si,2...Si,P Di,1 Di,2...Di,P, where Qi specifies performance, Si,j— input specification for part j, Di,k — output specification for part k.
Constraints
1 ≤ P ≤ 10, 1 ≤ N ≤ 50, 1 ≤ Qi ≤ 10000
Output
Output the maximum possible overall performance, then M — number of connections that must be made, then M descriptions of the connections. Each connection between machines A and B must be described by three positive numbers A B W, where W is the number of computers delivered from A to B per hour.
If several solutions exist, output any of them.
Sample Input
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 input 2 3 5 5 0 0 0 0 1 0 100 0 1 0 1 0 1 3 0 1 0 1 1 0 1 1 0 1 1 1 0 300 1 1 2 1 1 1 Sample input 3 2 2 100 0 0 1 0 200 0 1 1 1
Sample Output
Sample output 1 25 2 1 3 15 2 3 10 Sample output 2 4 5 1 3 3 3 5 3 1 2 1 2 4 1 4 5 1 Sample output 3 0 0
Hint
Source
建图还是比较明显的
首先就是建立一个s,t点,作为源点和汇点,那什么点该和汇点和源点相连
很明显,当一个点的入度都是0序列(其中可夹杂2,2说明对来源可以无所谓),与s点相连,边长当然是无穷大
当一点的出度都是1序列的时候,与t点相连,边长也为无穷大
如果一个i点的出度和j点的入度匹配,那么i+n和j连边,边长依然为无穷大
那就要问了,每台机器都有他自己的性能限制,这该怎么保证呢?
那么可以拆点,老样子拆点为i+n,i两个,连边为他的性能,这样就可以保证每台机器生产的机器数量了,挺简单的
接着就是输出最后的增广路径了
题目没有说要输出路径最小的,而是说输出满足题意的即可。
那么可以在最早建边的时候,在结构体中加入几个变量,记录。当每次增广后,记录每次增广的边,加和减与构造残留网络刚好相反,因为我只是单纯的想记住有多少流量从A点流向B点,仅次而已
接着从头扫道后,即可出来答案了额
到后来WA了两次,看了别人的题解,竟然最后还要换行,不知道是不是我没看清楚题目,加了换行,就过了
现在还有一个疑惑,不拆点能不能过呢?如果是生产一台电脑需要多个机器搭配,那就挺困难的,不拆点。再想想吧
#include<cstdio>
#include<cstring>
const int N=1010;
const int M=50001;
const int inf=0x7fffffff;
int head[N];
struct Edge
{
int v,next,w;
int a,b,flow;
} edge[M];
struct com
{
int p;
int jin[11];
int chu[11];
} d[51];
int cnt,n,s,t;
void addedge(int u,int v,int w,int a,int b)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].a=a;
edge[cnt].b=b;
edge[cnt].flow=0;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].v=u;
edge[cnt].w=0;
edge[cnt].a=a;
edge[cnt].b=b;
edge[cnt].flow=0;
edge[cnt].next=head[v];
head[v]=cnt++;
}
int sap()
{
int pre[N],cur[N],dis[N],gap[N];
int flow=0,aug=inf,u;
bool flag;
for(int i=0; i<n; i++)
{
cur[i]=head[i];
gap[i]=dis[i]=0;
}
gap[s]=n;
u=pre[s]=s;
while(dis[s]<n)
{
flag=0;
for(int &j=cur[u]; j!=-1; j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].w>0&&dis[u]==dis[v]+1)
{
flag=1;
if(edge[j].w<aug) aug=edge[j].w;
pre[v]=u;
u=v;
if(u==t)
{
flow+=aug;
while(u!=s)
{
u=pre[u];
edge[cur[u]].w-=aug;
edge[cur[u]].flow+=aug;
edge[cur[u]^1].w+=aug;
edge[cur[u]^1].flow-aug;
}
aug=inf;
}
break;
}
}
if(flag) continue;
int mindis=n;
for(int j=head[u]; j!=-1; j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].w>0&&dis[v]<mindis)
{
mindis=dis[v];
cur[u]=j;
}
}
if((--gap[dis[u]])==0)
break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return flow;
}
int ans[50000][3];
void output(int n)
{
int e=0;
for(int i=0; i<cnt; i++)
{
int a=edge[i].a;
int b=edge[i].b;
if(a!=b&&edge[i].flow>0)
{
ans[e][0]=a;
ans[e][1]=b;
ans[e][2]=edge[i].flow;
e++;
}
}
printf("%d/n",e);
for(int i=0; i<e; i++)
{
printf("%d %d %d/n",ans[i][0],ans[i][1],ans[i][2]);
}
printf("/n");//注意换行,没换行,竟然WA了两次而不是PE,我真的没找道题目哪里要说换行了
}
int main()
{
int p;
while(scanf("%d%d",&p,&n)!=EOF)
{
s=0;
t=2*n+1;
memset(head,-1,sizeof(head));
cnt=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&d[i].p);
for(int j=1; j<=p; j++) scanf("%d",&d[i].jin[j]);
for(int j=1; j<=p; j++) scanf("%d",&d[i].chu[j]);
}
for(int i=1; i<=n; i++)
{
bool flag=true;
for(int j=1; j<=p; j++)
if(d[i].jin[j]==1)
{
flag=false;
break;
}
if(flag) addedge(0,i,inf,0,0);
}
for(int i=1; i<=n; i++)
{
bool flag=true;
for(int j=1; j<=p; j++)
if(d[i].chu[j]!=1)
{
flag=false;
break;
}
if(flag) addedge(i+n,2*n+1,inf,0,0);
}
for(int i=1; i<=n; i++) addedge(i,i+n,d[i].p,i,i);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
bool flag=true;
for(int k=1; k<=p; k++) //p[i].chu[k]==2加不加无所谓
if(d[j].jin[k]!=2&&d[i].chu[k]!=d[j].jin[k])
{
flag=false;
break;
}
if(flag) addedge(i+n,j,inf,i,j);
}
int nn=n;
n=2*n+2;
printf("%d ",sap());
output(nn);
}
return 0;
}