思路:
很裸的一个最小费用流的问题.
我们建图:
①建立源点,连入各个节点,花费为-c【i】,流为d【i】。
②建立汇点,将各个节点连入汇点,花费为a【i】,流为b【i】。
③将图的边(u,v)加到网络中,花费为w,流为INF。
然后连续最短路跑费用流就行了,值得注意的一个坑点是,我们如果从源点到汇点的距离大于0的时候,我们这条边如果走过去了就相当于赔钱了。
所以当dis【tt】>0的时候,我们终止跑费用流。
Ac代码:
#include
using namespace std;
struct node
{
int from;
int to;
int w;
int f;
int num;
int next;
}e[2000000];
int dist[505][505];
int head[10000];
int vis[10000];
int dis[10000];
int pre[10000];
int path[10000];
int n,m,kk,cont,ss,tt;
void add(int from,int to,int f,int w)
{
e[cont].to=to;
e[cont].f=f;
e[cont].w=w;
e[cont].num=cont;
e[cont].next=head[from];
head[from]=cont++;
}
int SPFA()
{
for(int i=1;i<=tt;i++)dis[i]=0x3f3f3f3f;
dis[ss]=0;
memset(vis,0,sizeof(vis));
queues;
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&&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]>0)return 0;
else return 1;
}
void MCMF()
{
int ans=0;
int maxflow=0;
while(SPFA()==1)
{
int minn=0x3f3f3f3f;
for(int i=tt;i!=ss;i=pre[i])
{
minn=min(e[path[i]].f,minn);
}
for(int i=tt;i!=ss;i=pre[i])
{
e[path[i]].f-=minn;
e[path[i]^1].f+=minn;
}
ans+=minn*dis[tt];
maxflow+=minn;
}
printf("%d\n",-ans);
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
ss=n+1;
tt=ss+1;
cont=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dist[i][j]=0x3f3f3f3f;
}
dist[i][i]=0;
}
for(int i=1;i<=n;i++)
{
int aa,bb,cc,dd;
scanf("%d%d%d%d",&aa,&bb,&cc,&dd);
add(ss,i,dd,-cc);
add(i,ss,0,cc);
add(i,tt,bb,aa);
add(tt,i,0,-aa);
}
for(int i=1;i<=m;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
dist[x][y]=min(dist[x][y],w);
dist[y][x]=min(dist[y][x],w);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(dist[i][j]==0x3f3f3f3f)continue;
add(i,j,0x3f3f3f3f,dist[i][j]);
add(j,i,0,-dist[i][j]);
}
}
MCMF();
}
}