用网络流最大流算法解决。
本题看似有多个源点(发电站np)和多个汇点(用户nc),其实不然,我们只需添加s源点,t汇点,s连接np各点,其权值为发电量,nc各点连接t,其权值为用电量。
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<queue>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=1e2+10;
const int inf=0x3f3f3f3f;
int head[maxn],cur[maxn],cnt;
int pre[maxn],gap[maxn];
bool vis[maxn];
int n,np,nc,m;
struct Edge
{
int from,to,cap,next;
}e[2*maxn*maxn]; //2倍!!!经常要忘记而RE
struct ISAP
{
int s,t,dis[maxn];
bool bfs()
{
for(int i=0;i<=n+2;++i) vis[i]=0; //尽量不要用memset,题目要是卡常的话容易TLE的(本题就是,用memset会超时,不用79MS秒过)
queue<int> Q;
Q.push(t);
dis[t]=0; vis[t]=1; //记得是dis[t]=0,不是dis[s]=0,因为这个WA了好久
while(!Q.empty())
{
int fro=Q.front(); Q.pop();
for(int i=head[fro]; i ; i=e[i].next)
{
Edge& ed=e[i^1]; //取反边
if(!vis[ed.from])
{
vis[ed.from]=1;
dis[ed.from]=dis[fro]+1;
Q.push(ed.from);
}
}
}
return vis[s];
}
int augment()
{
int u=t, minflow=inf;
while(u!=s)
{
minflow=min(minflow,e[pre[u]].cap);
u=e[pre[u]].from;
}
u=t;
while(u!=s)
{
e[pre[u]].cap-=minflow;
e[pre[u]^1].cap+=minflow;
u=e[pre[u]].from;
}
return minflow;
}
int max_flow()
{
int flow=0;
for(int i=0;i<=n+2;++i) cur[i]=head[i],gap[i]=0;
bfs();
for(int i=0;i<=n+2;++i) gap[dis[i]]++;
int u=s;
while(dis[s]<n+2)
{
if(u==t)
{
flow+=augment();
u=s;
}
bool flag=0;
for(int i=cur[u]; i ;i=e[i].next)
{
if(e[i].cap&&dis[u]==dis[e[i].to]+1)
{
flag=1;
pre[e[i].to]=i;
cur[u]=i;
u=e[i].to;
break;
}
}
if(!flag)
{
int m=n+2-1;
for(int i=head[u]; i ;i=e[i].next)
{
if(e[i].cap)
m=min(m,dis[e[i].to]);
}
if(--gap[dis[u]]==0) break;
gap[dis[u]=m+1]++;
cur[u]=head[u];
if(u!=s) u=e[pre[u]].from;
}
}
return flow;
}
}isap;
void addedge(int u,int v,int w)
{
e[cnt].from=u; e[cnt].to=v; e[cnt].cap=w; e[cnt].next=head[u]; head[u]=cnt++;
e[cnt].from=v; e[cnt].to=u; e[cnt].cap=0; e[cnt].next=head[v]; head[v]=cnt++;
}
void init()
{
memset(head,0,sizeof(head));
isap.s=n; isap.t=n+1; cnt=2;
char s[maxn];
for(int i=1;i<=m;i++)
{
scanf("%s",s);
int a=0,b=0,c=0,len=strlen(s);
int temp=1,k=1;
for(int j=len-1;j>=0;j--)
{
if(isdigit(s[j]))
{
if(k==1)
c+=temp*(s[j]-'0');
else if(k==2)
b+=temp*(s[j]-'0');
else a+=temp*(s[j]-'0');
temp*=10;
}
else
{
temp=1;
k++;
}
}
addedge(a,b,c);
}
for(int i=1;i<=np;i++)
{
scanf("%s",s);
int a=0,b=0,len=strlen(s);
int temp=1,k=1;
for(int j=len-1;j>=0;j--)
{
if(isdigit(s[j]))
{
if(k==1)
b+=temp*(s[j]-'0');
else a+=temp*(s[j]-'0');
temp*=10;
}
else
{
temp=1;
k++;
}
}
addedge(isap.s,a,b);
}
for(int i=1;i<=nc;i++)
{
scanf("%s",s);
int a=0,b=0,len=strlen(s);
int temp=1,k=1;
for(int j=len-1;j>=0;j--)
{
if(isdigit(s[j]))
{
if(k==1)
b+=temp*(s[j]-'0');
else a+=temp*(s[j]-'0');
temp*=10;
}
else
{
temp=1;
k++;
}
}
addedge(a,isap.t,b);
}
}
int main()
{
while(~scanf("%d%d%d%d",&n,&np,&nc,&m))
{
init();
printf("%d\n",isap.max_flow());
}
return 0;
}