传送门115
传送门116
传送门117
题解:
一时半会不想写题于是打算搞事情 | 谁说我这是正儿八经给别人看了
明明学这玩意过去这么久了怎么现在才开始把板子放上来啊
很容易想到可以把每条边的容量变成up-low。但是因为这之后流量不守恒,再搞一个超级源点s和超级汇点t,然后记录一下每个点的val[i]=in[i](入流下界之和)-out[i](出流下界之和)。
当val[i]>0,s到i连边,容量val[i];当val[i]<0,i到t连边,容量-val[i]。
然后对s,t求最大流。当从s出去的边全部满流时有解。
代码:
#include
#include
#include
#define maxn 205
#define maxm 50005
#define INF 0x3f3f3f3f
using namespace std;
int n,m,s,t,val[maxn],flow,dist[maxn],cur[maxn],head[maxn],ncnt,ans[maxm],L[maxm];
struct node { int v,i,cap,nxt; } e[maxm];
void addedge(int u,int v,int i,int cap)
{
ncnt++;
e[ncnt].v=v,e[ncnt].cap=cap,e[ncnt].i=i,e[ncnt].nxt=head[u];
head[u]=ncnt;
}
void Add(int u,int v,int i,int w) { addedge(u,v,i,w); addedge(v,u,0,0); }
bool bfs()
{
for(int i=0;i<=t;i++) dist[i]=-1,cur[i]=head[i];
queue<int> q;
dist[s]=0; q.push(s);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int p=head[u];p;p=e[p].nxt)
{
int v=e[p].v;
if(dist[v]>=0||!e[p].cap) continue;
dist[v]=dist[u]+1; q.push(v);
}
}
return dist[t]>=0;
}
int dfs(int u,int Cap)
{
if(u==t||!Cap) return Cap;
int flow=0;
for(int &p=cur[u];p;p=e[p].nxt)
{
int v=e[p].v;
if(dist[v]==dist[u]+1)
{
int f=dfs(v,min(e[p].cap,Cap));
if(!f) continue;
flow+=f,Cap-=f,e[p].cap-=f,e[p^1].cap+=f;
if(!Cap) break;
}
}
return flow;
}
void dinic()
{
while(bfs()) flow+=dfs(s,INF);
}
int main()
{
scanf("%d%d",&n,&m); ncnt=1;
for(int i=1;i<=m;i++)
{
int u,v,l,r;
scanf("%d%d%d%d",&u,&v,&l,&r);
Add(u,v,i,r-l); val[u]-=l,val[v]+=l,L[i]=l;
}
s=0,t=n+1;
for(int i=1;i<=n;i++)
if(val[i]>0) Add(s,i,0,val[i]);
else if(val[i]<0) Add(i,t,0,-val[i]);
dinic();
for(int p=head[s];p;p=e[p].nxt)
if(e[p].cap) { printf("NO\n"); return 0; }
for(int i=2;i<=ncnt;i++) ans[e[i].i]=e[i^1].cap;
printf("YES\n");
for(int i=1;i<=m;i++) printf("%d\n",ans[i]+L[i]);
}
题解:
语死早表示这玩意怎么可能是别人能看的
我们先跑一发可行流。
可以从t到s连一条容量INF的边,转化成无源汇有上下界最大流,那么跑完之后s到t的权值即为所求。
然后在残量网络上跑s-t最大流即可。
所求为二者之和。
代码:
#include
#include
#include
#define maxn 205
#define maxm 50005
#define INF 0x3f3f3f3f
using namespace std;
int n,m,s,t,val[maxn],flow,dist[maxn],cur[maxn],head[maxn],ncnt,ans[maxm],L[maxm],s0,t0;
struct node { int v,i,cap,nxt; } e[maxm];
void addedge(int u,int v,int cap)
{
ncnt++;
e[ncnt].v=v,e[ncnt].cap=cap,e[ncnt].nxt=head[u];
head[u]=ncnt;
}
void Add(int u,int v,int w) { addedge(u,v,w); addedge(v,u,0); }
bool bfs()
{
for(int i=0;i<=t;i++) dist[i]=-1,cur[i]=head[i];
queue<int> q;
dist[s]=0; q.push(s);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int p=head[u];p;p=e[p].nxt)
{
int v=e[p].v;
if(dist[v]>=0||!e[p].cap) continue;
dist[v]=dist[u]+1; q.push(v);
}
}
return dist[t]>=0;
}
int dfs(int u,int Cap)
{
if(u==t||!Cap) return Cap;
int flow=0;
for(int &p=cur[u];p;p=e[p].nxt)
{
int v=e[p].v;
if(dist[v]==dist[u]+1)
{
int f=dfs(v,min(e[p].cap,Cap));
if(!f) continue;
flow+=f,Cap-=f,e[p].cap-=f,e[p^1].cap+=f;
if(!Cap) break;
}
}
return flow;
}
void dinic()
{
while(bfs()) flow+=dfs(s,INF);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s0,&t0); ncnt=1;
for(int i=1;i<=m;i++)
{
int u,v,l,r;
scanf("%d%d%d%d",&u,&v,&l,&r);
Add(u,v,r-l); val[u]-=l,val[v]+=l,L[i]=l;
}
s=0,t=n+1;
for(int i=1;i<=n;i++)
if(val[i]>0) Add(s,i,val[i]);
else if(val[i]<0) Add(i,t,-val[i]);
Add(t0,s0,INF);
dinic();
for(int p=head[s];p;p=e[p].nxt)
if(e[p].cap) { printf("please go home to sleep\n"); return 0; }
for(int i=1;i<=n;i++)
for(int p=head[i];p;p=e[p].nxt)
if(e[p].v==t||e[p].v==s) e[p].cap=e[p^1].cap=0;
for(int p=head[s0];p;p=e[p].nxt)
if(e[p].v==t0) { flow=e[p].cap,e[p].cap=e[p^1].cap=0; }
s=s0,t=t0;
dinic();
printf("%d\n",flow);
}
题解:
求完可行流后跑t-s最大流,二者相减即为所求。
代码:
#include
#include
#include
#define maxn 50010
#define maxm 500005
#define LL long long
#define INF (LL)1e16
using namespace std;
int n,m,s,t,val[maxn],dist[maxn],cur[maxn],head[maxn],ncnt,ans[maxm],L[maxm],s0,t0;
LL flow;
struct node { int v,i,nxt; LL cap; } e[maxm];
void addedge(int u,int v,LL cap)
{
ncnt++;
e[ncnt].v=v,e[ncnt].cap=cap,e[ncnt].nxt=head[u];
head[u]=ncnt;
}
void Add(int u,int v,LL w) { addedge(u,v,w); addedge(v,u,0); }
bool bfs()
{
for(int i=0;i<=n+1;i++) dist[i]=-1,cur[i]=head[i];
queue<int> q;
dist[s]=0; q.push(s);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int p=head[u];p;p=e[p].nxt)
{
int v=e[p].v;
if(dist[v]>=0||!e[p].cap) continue;
dist[v]=dist[u]+1; q.push(v);
}
}
return dist[t]>=0;
}
LL dfs(int u,LL Cap)
{
if(u==t||!Cap) return Cap;
LL flow=0;
for(int &p=cur[u];p;p=e[p].nxt)
{
int v=e[p].v;
if(dist[v]==dist[u]+1)
{
LL f=dfs(v,min(e[p].cap,Cap));
if(!f) continue;
flow+=f,Cap-=f,e[p].cap-=f,e[p^1].cap+=f;
if(!Cap) break;
}
}
return flow;
}
void dinic()
{
while(bfs()) flow-=dfs(s,INF);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s0,&t0); ncnt=1;
for(int i=1;i<=m;i++)
{
int u,v,l,r;
scanf("%d%d%d%d",&u,&v,&l,&r);
Add(u,v,r-l); val[u]-=l,val[v]+=l,L[i]=l;
}
s=0,t=n+1;
for(int i=1;i<=n;i++)
if(val[i]>0) Add(s,i,val[i]);
else if(val[i]<0) Add(i,t,-val[i]);
Add(t0,s0,INF);
dinic();
for(int p=head[s];p;p=e[p].nxt)
if(e[p].cap) { printf("please go home to sleep\n"); return 0; }
for(int i=1;i<=n;i++)
for(int p=head[i];p;p=e[p].nxt)
if(e[p].v==t||e[p].v==s) e[p].cap=e[p^1].cap=0;
for(int p=head[s0];p;p=e[p].nxt)
if(e[p].v==t0) flow=e[p].cap,e[p].cap=e[p^1].cap=0;
s=t0,t=s0;
dinic();
printf("%lld\n",flow);
}