JZOJ 3302. 【集訓隊互測2013】供電網絡

DescriptionDescription

形如下列問題
出來吧
求讓所有點的電量都爲0的最小花費
數據範圍:
n200,m600n \leq 200, m \leq 600
uv,1u,vn,1a,b3,1L10,1LU100u \neq v, 1 \leq u, v \leq n, 1 \leq a, b \leq3, 1 \leq L \leq 10, 1 \leq L \leq U \leq 100
0in,out100,5left5.0 \leq in, out \leq 100, -5 \leq left \leq 5.


SolutionSolution

考場時打了一個10分的bfsbfs

當時曾想過網絡流,但一建圖發現是有上下界並且要求最小費用最小流,立馬就懵逼了,完全不會做呀QwQ

後來才發現“最小流”是求解上下界費用流的問題種類之一呢

好了不扯淡了,開始講建圖

首先把電理解爲流量

對於買入賣出,可以理解爲源點和匯點一個分別無限供應,無限接收,得到邊

(S,i,,in)(S,i,\infty,in)表示可以從源點無限買入,代價爲inin
(i,T,,out)(i,T,\infty,out)表示可以向匯點無限輸入,代價爲outout
但注意到這樣跑最小費用最大流是有問題的,因爲容量太大,會導致費用炸鍋。

所以我們不能按傳統的費用流跑,而是得一瓦一瓦電流過去,反正電流的絕對值不超過5嘛

然後考慮邊連接的點,注意到傳遞只能傳遞一次,傳遞的代價是一個可以遞推的量
但是如果我們不斷建邊可能會炸,所以動態建邊即可(即臨時改變邊流量【或重新建】)

最後考慮每個點的初始流量怎麼設定呢?由於是最小費用最大流,我們令其費用爲無窮小,醬紫的話就強制要求了這個剩餘流量必定流入

但是醬紫答案會是負數呢?實際上對\infty取模後就可以把減去的部分搞掉了呢,不過注意\infty別取太大,不然就會像我一樣爆intint導致85分

最後判斷結束條件即爲結果大於0時(即無法流入時)


CodeCode

#include<map>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define N 210
using namespace std;
inline int read()
{
    int f=0,d=1;char c;
    while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
    return d*f;
}
int n,m,rst[N],mr,mc,s,t;
long long ans2;
struct node{int next,to,w,g;}e[610*20];
int dis[N],l[N],fa[N],tot=1,pos[N],bj[N][N];
int u[610],v[610],a[610],b[610],up[610],down[610];
bool vis[N];
inline void add(int u,int v,int w,int c)
{
    e[++tot]=(node){l[u],v,w,c};l[u]=tot;
    e[++tot]=(node){l[v],u,0,-c};l[v]=tot;
    return;
}
inline bool spfa()
{
	for(register int i=1;i<=m;i++)
	 if(bj[u[i]][v[i]]==down[i]&&down[i]<up[i])
	  down[i]++,add(u[i],v[i],1,a[i]*(2*down[i]-1)+b[i]);
    memset(dis,0x3f,sizeof(dis));
    queue<int>q;q.push(s);dis[s]=0;
    while(q.size())
    {
        int x=q.front();q.pop();vis[x]=false;
        for(int i=l[x];i;i=e[i].next)
        {
            int y=e[i].to,w=e[i].g;
            if(e[i].w&&dis[y]>dis[x]+w)
            {
                dis[y]=dis[x]+w;
                pos[y]=i;fa[y]=x;
                if(!vis[y]) q.push(y),vis[y]=true;
            }
        }
    }
    return dis[t]<=0;
}
void updata()
{
    for(int i=t;i!=s;i=fa[i])
    {
        int x=pos[i];
        e[x].w--;
        e[x^1].w++;
		bj[e[x^1].to][e[x].to]++;
        bj[e[x].to][e[x^1].to]--;
    }
    ans2+=dis[t];
    return;
}
inline void EK(){while(spfa())updata();return;}
signed main()
{
	n=read();m=read();s=n+1;t=s+1;
	for(register int i=1;i<=n;i++) 
	{
		rst[i]=read();mr=read();mc=read();
		add(s,i,1e6,mr);
		add(i,t,1e6,mc);
	}
	for(register int i=1;i<=m;i++)
	{
		u[i]=read();v[i]=read();a[i]=read();b[i]=read();
		down[i]=read();up[i]=read();
		rst[u[i]]-=down[i];rst[v[i]]+=down[i];
		ans2+=a[i]*down[i]*down[i]+b[i]*down[i];
		bj[u[i]][v[i]]+=down[i];
		bj[v[i]][u[i]]-=down[i];
	}
	for(register int i=1;i<=n;i++) 
	 if(rst[i]>0) add(s,i,rst[i],-1e6);
	  else add(i,t,-rst[i],-1e6);
	EK();
	ans2%=1000000;
	if(ans2<0) ans2+=1e6;
	printf("%lld",ans2);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章