网络流的一些注意事项
具体可以看这位大佬
1.1
最大(瘤)流
1.1.1----ACM Computer Factory POJ - 3436(点有限制拆点,边无限制)
题意:
有一个电脑的生产线,要你优化生产线。
思路:
- 对于每台机器都有一个生产量, Q i Qi Qi。(把机器抽象成点,就是点有限制,要拆点)
- 如果一台机器的输入 没有包含 “1”,那么就说明这台机器可以和源点 S S S相连。(inf)
- 如果一台机器的输出有一个零件不能生成,那么它就不能和汇点 T T T相连。(inf)
- 对于一个机器的输出是否可以传递到下一个机器的输入,这里要判断一下,是否要连边。(inf)
- 最后就是按照最大流的计算结果,查看边是否有流量,有+flow,那么说明机器有conection(这里要注意一些边界的判断)。
AC
#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <cstdio>
//#include <>
#include <algorithm>
//#include <>
#define sz(a) ((int)a.size())
#define pb push_back
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define eb emplace_back
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead EDGE(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c),flow(f)
using namespace std;
const int N=100+10;
const int maxn=100+10;
const int M=0;
const int inf=0x3f3f3f3f;
struct EDGE{
int from,to,cap,flow;
EDGE(){}
fzhead:fzbody{}
};
struct Dinic{
int n,m,s,t;
vector<EDGE> edges;
vector<int> g[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
///cur就是记录当前循环到了哪一条边。
void init(int n){
this->n = n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
void add(int from, int to, int cap){
// edges.eb(from,to,cap,0);
//edges.eb(to,from,0,0);
edges.pb({from,to,cap,0});
edges.pb({to,from,0,0});
///加边同时,加正向和反向。
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
bool bfs(){
mst(vis,0);
mst(d,0);
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=1;///源点深度为1.
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=0; i<sz(g[x]); i++)
{
EDGE&e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];///当汇点的深度不存在时,说明不存在分层图。
}
int dfs(int x, int a){
///x为当前节点,a为流量。
if(x==t || a==0)return a;///当已经到达汇点,或者流量不存在时,返回。
int flow=0,f;
for(int &i=cur[x]; i<sz(g[x]); i++){
///注意这里的“&”符号,这样i增加同时也能改变cur【x】的值,达到弧优化的目的。
EDGE& e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){///判断并且增广。
e.flow+=f;///加减
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}
return flow;
}
int maxflow(int s, int t){
this->s=s,this->t=t;
int flow=0;
while(bfs()){
///每一次建立分层图后,都要把cur置为每一个点的第一条边
mst(cur,0);
flow+=dfs(s,inf);
}
return flow;
}
} dinic;
int n,p;
int a[maxn][20];
int w[maxn];
int main()
{
while(~scanf("%d%d",&p,&n)){
dinic.init(maxn);
int s=2*n+1;
int t=2*n+2;
For(i,1,n){
scanf("%d",w+i);
For(j,1,p)scanf("%d",a[i]+j);
For(j,1,p)scanf("%d",a[i+n]+j);
}
//cout<<"ok"<<endl;
For(i,1,n)dinic.add(i,i+n,w[i]);
For(i,1,n){
bool fl=true;
For(j,1,p)if(a[i][j]==1)fl=false;
if(fl)dinic.add(s,i,inf);
}
For(i,n+1,2*n){
bool fl=true;
For(j,1,p)if(a[i][j]!=1)fl=false;
if(fl)dinic.add(i,t,inf);
}
For(i,n+1,2*n){
For(j,1,n){
bool fl=true;
For(k,1,p){
if(a[i][k]==a[j][k])continue;
if(a[j][k]==2)continue;
fl=false;
}if(fl)dinic.add(i,j,inf);
}
}
// cout<<"ok"<<endl;
int ans=dinic.maxflow(s,t);
//cout<<"ok"<<endl;
vector<EDGE>anss;
vector<EDGE> &e=dinic.edges;
for(int i=0; i<sz(e); i++){
if(e[i].from<=n||e[i].from==s)continue;
if(e[i].to>=n+1)continue;
if(e[i].flow>0)anss.push_back({e[i].from-n,e[i].to,0,e[i].flow});
}
printf("%d %d\n",ans,sz(anss));
for(int i=0; i<sz(anss); i++)printf("%d %d %d\n",anss[i].from,anss[i].to,anss[i].flow);
}
return 0;
}
1.1.2----Dining POJ - 3281(点有限制–拆点,边有限制-容量为限制)
题意:
农夫有
n
n
n头奶牛,有
f
f
f个食物,有
d
d
d个drink
对于每头奶牛有喜欢的
f
o
o
d
food
food和
d
r
i
n
k
drink
drink
如何分配,求可以使最多奶牛满足。
思路:
由于奶牛只有一头,点有限制,拆点,其它就是模板。
而食物和drink只有一种,那么边的容量就为限制。
笔记
拆点体会。
对于下图
如果从
f
o
o
d
1
food1
food1 到
d
r
i
n
k
2
drink2
drink2 操作完后,是这样。
但下次增广时,在碰到这头cow,由于没有进行拆点
牛还是会进行
f
o
o
d
2
food2
food2 到
d
r
i
n
k
1
drink1
drink1
AC
#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <cstdio>
#include <algorithm>
#define sz(a) ((int)a.size())
#define pb push_back
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define eb emplace_back
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead EDGE(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int N=100+10;
const int maxn=100+200+100+10;
const int M=0;
const int inf =0x3f3f3f3f;
struct EDGE{
int from,to,cap,flow;
EDGE(){}
fzhead:fzbody{}
};
struct Dinic{
int n,m,s,t;
vector<EDGE> edges;
vector<int> g[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
///cur就是记录当前循环到了哪一条边。
void init(int n){
this->n = n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
void add(int from, int to, int cap){
// edges.eb(from,to,cap,0);
//edges.eb(to,from,0,0);
edges.pb({from,to,cap,0});
edges.pb({to,from,0,0});
///加边同时,加正向和反向。
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
bool bfs(){
mst(vis,0);
mst(d,0);
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=1;///源点深度为1.
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=0; i<sz(g[x]); i++)
{
EDGE&e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];///当汇点的深度不存在时,说明不存在分层图。
}
int dfs(int x, int a){
///x为当前节点,a为流量。
if(x==t || a==0)return a;///当已经到达汇点,或者流量不存在时,返回。
int flow=0,f;
for(int &i=cur[x]; i<sz(g[x]); i++){
///注意这里的“&”符号,这样i增加同时也能改变cur【x】的值,达到弧优化的目的。
EDGE& e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){///判断并且增广。
e.flow+=f;///加减
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}
return flow;
}
int maxflow(int s, int t){
this->s=s,this->t=t;
int flow=0;
while(bfs()){
///每一次建立分层图后,都要把cur置为每一个点的第一条边
mst(cur,0);
flow+=dfs(s,inf);
}
return flow;
}
} dinic;
int n,f,d;
int main()
{
int s=0, t=401,x;
dinic.init(maxn);
scanf("%d%d%d", &n,&f,&d);
For(i,1,f)dinic.add(s,i,1);
For(i,1,d)dinic.add(i+300,t,1);
For(i,1,n)dinic.add(i+100,i+200,1);
For(i,1,n)
{
scanf("%d%d", &f, &d);
For(j,1,f){
scanf("%d", &x);
dinic.add(x,i+100,1);
}
For(j,1,d){
scanf("%d", &x);
dinic.add(i+200,x+300,1);
}
}
int ans=dinic.maxflow(s,t);
printf("%d\n",ans);
return 0;
}
1.1.3----A Plug for UNIX POJ - 1087(建图)
题意:
来自
hrbustacm2 019-04-11
AS WE ALL KNOW,最近哈理工出现了一起着火事件,原因是用了杂牌的插座,有着强烈安全意识的鑫爹急忙为G808换上了最牛B的红牛插座。假设他买了n种插座,G808有m个电器,分别有自己可以插的插座。由于鑫爹的插座非常牛B,可以相互转换,接下来给出k行说明S1插座和S2插座把S2换成S1,那么最少有几个电器没有插座用呢?
思路:
源点
−
>
->
−> 插座S
−
>
->
−> 设备
−
>
->
−> 汇点
------ 1----------- 1----------- 1
有k个转换器,由于没有限制个数,所以
S
2
S2
S2
−
>
->
−>
S
1
S1
S1
------
i
n
f
inf
inf
AC
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <map>
#include <string>
#define sz(a) ((int)a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead EDGE(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int N =100+10;
const int maxn=400+10;
const int M=0;
const int inf=0x3f3f3f3f;
struct EDGE{
int from,to,cap,flow;
EDGE(){}
fzhead:fzbody{}
};
struct Dinic{
int n,m,s,t;
vector<EDGE> edges;
vector<int> g[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n){
this->n=n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
void add(int from, int to, int cap){
edges.pb({from,to,cap,0});
edges.pb({to,from,0,0});
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
bool bfs(){
mst(vis,0);
mst(d,0);
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0; i<sz(g[x]); i++){
EDGE& e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}return vis[t];
}
int dfs(int x,int a){
if(x==t||a==0)return a;
int flow=0,f;
for(int &i=cur[x]; i<sz(g[x]); i++){
EDGE& e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
e.flow+=f;
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}return flow;
}
int maxflow(int s, int t){
this->s=s,this->t=t;
int flow=0;
while(bfs()){
mst(cur,0);
flow+=dfs(s,inf);
}
return flow;
}
} dinic;
map<string,int>ma;
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n,m,k;
cin>>n;
dinic.init(maxn);
int tot=0,s=0,t=401;
string x,x1;
For(i,1,n){
cin>>x;
if(!ma.count(x)){ma[x]=++tot;dinic.add(s,ma[x],1);}
}
cin>>m;
For(i,1,m){
cin>>x>>x1;
if(!ma.count(x))ma[x]=++tot;
if(!ma.count(x1))ma[x1]=++tot;
dinic.add(ma[x1],ma[x],1);
dinic.add(ma[x],t,1);
}
cin>>k;
For(i,1,k){
cin>>x>>x1;
if(!ma.count(x))ma[x]=++tot;
if(!ma.count(x1))ma[x1]=++tot;
dinic.add(ma[x1],ma[x],inf);
}
int ans=m-dinic.maxflow(s,t);
cout<<ans<<endl;
return 0;
}
1.1.4----Power Network POJ - 1459(多源汇点&&多源)
思路:
板子题。
反思:
本题的读入。
- 关于char,可以直接
- 不过可以stringstream,不过慢一点。
AC
#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <vector>
#include <sstream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define pb push_back
#define sz(a) (int)(a.size())
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=1e2+10;
const int inf=0x3f3f3f3f;
struct Edge
{
int from,to,cap,flow;
Edge(){}
fzhead:fzbody{}
};
struct Dinic{
int n,m,s,t;
vector<Edge>edges;
vector<int>g[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n){
this->n=n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
void add(int from, int to, int cap){
edges.pb({from,to,cap,0});
edges.pb({to,from,0,0});
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
bool bfs(){
mst(vis,0);mst(d,0);
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0; i<sz(g[x]); i++){
Edge&e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x,int a){
if(x==t||a==0)return a;
int flow=0,f;
for(int &i=cur[x]; i<sz(g[x]); i++){
Edge&e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
e.flow+=f;
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}
return flow;
}
int maxflow(int s, int t){
this->s=s,this->t=t;
int flow=0;
while(bfs()){
mst(cur,0);
flow+=dfs(s,inf);
}
return flow;
}
} dinic;
int n,m,p,c;
int main()
{
while(~scanf("%d%d%d%d", &n, &p,&c, &m)){
dinic.init(maxn);
int s=101,t=102;
int u,v,z;
string str;
for(int i=1; i<=m; i++){
cin>>str;
for(int j=0; j<sz(str); j++)if(str[j]<'0'||str[j]>'9')str[j]=' ';
stringstream ss(str);
ss>>u>>v>>z;
// cout<<u<<' '<<v<<' '<<z<<endl;
dinic.add(u,v,z);
}
for(int i=1; i<=p; i++){
cin>>str;
for(int j=0; j<sz(str); j++)if(str[j]<'0'||str[j]>'9')str[j]=' ';
stringstream ss(str);
ss>>v>>z;
//cout<<v<<' '<<z<<endl;
dinic.add(s,v,z);
}
for(int i=1; i<=c; i++){
cin>>str;
for(int j=0; j<sz(str); j++)if(str[j]<'0'||str[j]>'9')str[j]=' ';
stringstream ss(str);
ss>>u>>z;
// cout<<u<<' '<<z<<endl;
dinic.add(u,t,z);
}
// cout<<"ok"<<endl;
printf("%d\n", dinic.maxflow(s,t));
}
return 0;
}
1.1.5----Island Transport HDU - 4280(本题卡dinic)
题意:
赤裸裸的模板。
AC
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#define sz(a) (int)(a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
const int maxm=2e5+10;
struct Edge {
int from, to, cap, flow;
Edge(){}// Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
fzhead:fzbody{}
};
//
bool operator<(const Edge& a, const Edge& b) {
return a.from < b.from || (a.from == b.from && a.to < b.to);
}
//
struct ISAP {
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
int p[maxn];
int num[maxn];
//
void add(int from, int to, int cap) {
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, cap, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
//
bool BFS() {
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(t);
vis[t] = 1;
d[t] = 0;
while (!Q.empty()) {
int x = Q.front();
Q.pop();
for (int i = 0; i < G[x].size(); i++) {
Edge& e = edges[G[x][i] ^ 1];
if (!vis[e.from] && e.cap > e.flow) {
vis[e.from] = 1;
d[e.from] = d[x] + 1;
Q.push(e.from);
}
}
}
return vis[s];
}
//
void init(int n) {
this->n = n;
for (int i = 0; i < n; i++) G[i].clear();
edges.clear();
}
//
int Augment() {
int x = t, a = inf;
while (x != s) {
Edge& e = edges[p[x]];
a = min(a, e.cap - e.flow);
x = edges[p[x]].from;
}
x = t;
while (x != s) {
edges[p[x]].flow += a;
edges[p[x] ^ 1].flow -= a;
x = edges[p[x]].from;
}
return a;
}
//
int maxflow(int s, int t) {
this->s = s;
this->t = t;
int flow = 0;
BFS();
memset(num, 0, sizeof(num));
for (int i = 0; i < n; i++) num[d[i]]++;
int x = s;
memset(cur, 0, sizeof(cur));
while (d[s] < n) {
if (x == t) {
flow += Augment();
x = s;
}
int ok = 0;
for (int i = cur[x]; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if (e.cap > e.flow && d[x] == d[e.to] + 1) {
ok = 1;
p[e.to] = G[x][i];
cur[x] = i;
x = e.to;
break;
}
}
if (!ok) {
int m = n - 1;
for (int i = 0; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if (e.cap > e.flow) m = min(m, d[e.to]);
}
if (--num[d[x]] == 0) break;
num[d[x] = m + 1]++;
cur[x] = 0;
if (x != s) x = edges[p[x]].from;
}
}
return flow;
}
} sap;
int n,m;
struct point{
int x,y;
int id;
}p[maxn];
int main()
{
int t;
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
sap.init(n+10);
int x,y;
point s={inf,inf,0},ed={0,0,0};
For(i,1,n){
scanf("%d%d", &x,&y);
p[i]={x,y,i};
if(p[i].x>ed.x)ed=p[i];
if(p[i].x<s.x)s=p[i];
}
int u,v,cap;
For(i,1,m){
scanf("%d%d%d", &u,&v, &cap);
sap.add(u,v,cap);
}
printf("%d\n",sap.maxflow(s.id,ed.id));
}
return 0;
}//
1.1.6----Food HDU - 4292(点有限制–拆点,边有限制-容量为限制)
题意:
与poj3281基本一样。
AC
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <cstdio>
#define sz(a) (int)(a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=1e3+10;
const int inf=0x3f3f3f3f;
struct Edge{
int from, to, cap, flow;
Edge(){}
fzhead:fzbody{}
};
struct Dinic{
int n,m,s,t;
vector<Edge>edges;
vector<int>g[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n){
this->n=n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
void add(int from, int to, int cap){
edges.pb({from,to,cap,0});
edges.pb({to,from,0,0});
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
bool bfs(){
mst(vis,0);mst(d,0);
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0; i<sz(g[x]); i++){
Edge&e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x,int a){
if(x==t||a==0)return a;
int flow=0,f;
for(int &i=cur[x]; i<sz(g[x]); i++){
Edge&e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
e.flow+=f;
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}
return flow;
}
int maxflow(int s,int t){
this->s=s,this->t=t;
int flow=0;
while(bfs()){
mst(cur,0);
flow+=dfs(s,inf);
}
return flow;
}
} dinic;
int n,f,d;
int a[300],b[300];
int main()
{
char str[300];
while(~scanf("%d%d%d", &n, &f, &d)){
dinic.init(maxn);
For(i,1,f)scanf("%d",a+i);
For(i,1,d)scanf("%d", b+i);
int s=0,t=801;
For(i,1,f)dinic.add(s,i,a[i]);
For(i,1,d)dinic.add(600+i,t,b[i]);
For(i,1,n){
scanf("%s", str+1);
for(int j=1; j<=f ;j++){
if(str[j]=='Y')dinic.add(j,i+200,1);
}
dinic.add(i+200,i+400,1);
}
For(i,1,n){
scanf("%s", str+1);
for(int j=1; j<=d; j++){
if(str[j]=='Y')dinic.add(i+400,j+600,1);
}
}
printf("%d\n", dinic.maxflow(s,t));
}
return 0;
}
1.1.7----Leapin’ Lizards HDU - 2732(点有限制)
题意:
- 蜥蜴lizard要逃出迷宫,初始时lizard都在柱子上。当lizard跳出柱子,原来的柱子受到磨损。当lizard跳上柱子,不磨损。
- 跳的距离为
Manhattan距离
- 假如在room的边缘,如果从柱子可以跳出迷宫,那么就安全。
思路:
板子。
反思:
本题输出有单复数
(lizard)
AC
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <algorithm>
#include <queue>
#define sz(a) (int)(a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=400*2+10;
const int inf=0x3f3f3f3f;
struct Edge{
int from, to, cap, flow;
Edge(){}
fzhead:fzbody{}
};
struct Dinic{
int n,m,s,t;
vector<Edge>edges;
vector<int>g[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n){
this->n=n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
void add(int from, int to, int cap){
edges.pb({from,to,cap,0});
edges.pb({to,from,0,0});
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
bool bfs(){
mst(vis,0);mst(d,0);
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0; i<sz(g[x]); i++){
Edge&e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x,int a){
if(x==t||a==0)return a;
int flow=0,f;
for(int i=0; i<sz(g[x]); i++){
Edge&e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
e.flow+=f;
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}
return flow;
}
int maxflow(int s, int t){
this->s=s,this->t=t;
int flow=0;
while(bfs()){
mst(cur,0);
flow+=dfs(s,inf);
}
return flow;
}
}dinic;
struct point{
int x,y;
};
int n,m,d;
int id(int i, int j){
return (i-1)*m+j;
}
char gap[40][40], lim[40][40];
int Lim[40][40];
int main()
{
int t,kase=0;
scanf("%d", &t);
while(t--){
int sum=0;
scanf("%d%d", &n, &d);
For(i,1,n)scanf("%s",lim[i]+1);
For(i,1,n)scanf("%s",gap[i]+1);
m=strlen(lim[1]+1);
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++)Lim[i][j]=lim[i][j]-'0';
}
dinic.init(maxn);
int s=0,ed=801;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(gap[i][j]=='L'){
int num=id(i,j);
dinic.add(s,num,1);
sum++;
}
}
}
vector<point>pal;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(Lim[i][j]){
int num=id(i,j);
pal.pb({i,j});//cachid[++cnt]=num;
dinic.add(num,num+400,Lim[i][j]);
if(i+d>n||i-d<=0||j+d>m||j-d<=0)dinic.add(num+400,ed,inf);//cout<<i<<' '<<j<<' '<<Lim[i][j]<<endl;
}
}
}
for(int i=0; i<sz(pal); i++){
for(int j=i+1; j<sz(pal); j++){
//if(i==j)continue;
int dis=abs(pal[i].x-pal[j].x)+abs(pal[i].y-pal[j].y);
int u_num=id(pal[i].x,pal[i].y);
int v_num=id(pal[j].x,pal[j].y);
if(dis<=d)dinic.add(v_num+400,u_num,inf),dinic.add(u_num+400,v_num,inf);
}
}
// cout<<sum<<endl;
int res=sum-dinic.maxflow(s,ed);
if(res>1)printf("Case #%d: %d lizards were left behind.\n", ++kase,res);
else if(res==1)printf("Case #%d: %d lizard was left behind.\n", ++kase,res);
else printf("Case #%d: no lizard was left behind.\n", ++kase);
}
return 0;
}
1.1.8----Kakuro Extension HDU - 3338(建图
,拆点)
(sap莫名wa,我也不懂)
2020-7-28找到问题了。原来没初始化。。。qwq
这位大佬有阐述问题的原因
思路:
看这里大佬的
AC1(dinic)
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <cmath>
#define sz(a) (int)(a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=5e4+10;
const int INF=0x3f3f3f3f;
const int maxm=2e5+10;
struct Edge {
int from, to, cap, flow;
Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
};
//
struct Dinic {
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
int d[maxn], cur[maxn];
bool vis[maxn];
//
void init(int n) {
for (int i = 0; i <= n; i++) G[i].clear();
edges.clear();
}
//
void add(int from, int to, int cap) {
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
//
bool BFS() {
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while (!Q.empty()) {
int x = Q.front();
Q.pop();
for (int i = 0; i < sz(G[x]); i++) {
Edge& e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow) {
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
//
int DFS(int x, int a) {
if (x == t || a == 0) return a;
int flow = 0, f;
for (int& i = cur[x]; i < sz(G[x]); i++) {
Edge& e = edges[G[x][i]];
if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
e.flow += f;
edges[G[x][i] ^ 1].flow -= f;
flow += f;
a -= f;
if (a == 0) break;
}
}
return flow;
}
//
int maxflow(int s, int t) {
this->s = s;
this->t = t;
int flow = 0;
while (BFS()) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, INF);
}
return flow;
}
}dinic;
//
int n,m;
int id(int i, int j){
return (i-1)*m+j;
}
int getval(char *s){
int res=0;
for(int i=1; i<=3; i++){
res*=10;
res+=s[i]-'0';
}
// cout<<res<<endl;
return res;
}
struct point{
int x,y;
int sta;//0:white 1:black 2:have value
int up,left;
}p[maxn];
int main()
{
while(~scanf("%d%d", &n, &m)){
dinic.init(maxn);mst(p,0);
char s[20];
int st=0,ed=2e4+10,dv=1e4;
For(i,1,n){
For(j,1,m){
scanf("%s", s+1);
int num=id(i,j);
p[num]={i,j,0,0,0};
if(s[1]=='.')continue;
if(s[4]=='X'){p[num].sta=1;continue;}
if(s[1]!='X')p[num].up=getval(s);
if(s[5]!='X')p[num].left=getval(s+4);
p[num].sta=3;
}
}
For(i,1,n){
For(j,1,m){
int num=id(i,j);
if(p[num].sta==3){
if(p[num].up){
//cout<<num<<endl;
vector<int>in;
int sum=0;
For(k,i+1,n){
if(p[id(k,j)].sta==0)sum++,in.pb(id(k,j));
else break;
}
p[num].up-=sum;
dinic.add(st,num,p[num].up);
for(int k=0; k<sz(in); k++)dinic.add(num,in[k],8);
}
if(p[num].left){
vector<int>in;
int sum=0;
For(k,j+1,m){
if(p[id(i,k)].sta==0)sum++,in.pb(id(i,k));
else break;
}
p[num].left-=sum;
dinic.add(num+dv,ed,p[num].left);
for(int k=0; k<sz(in); k++)dinic.add(in[k],num+dv,8);
}
}
}
}
//cout<<"ok1"<<endl;
dinic.maxflow(st,ed);
// cout<<"ok2"<<endl;
vector<Edge>&e=dinic.edges;
//int &vis=sap.p;
For(i,1,n){
For(j,1,m){
if(p[id(i,j)].sta!=0)printf("_ ");
else {
int num=dinic.G[id(i,j)][1];
printf("%d ",e[num].flow+1);
}
}
printf("\n");
}
}
return 0;
}
AC2(isap)
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <cmath>
#define sz(a) (int)(a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=5e4+10;
const int inf=0x3f3f3f3f;
const int maxm=2e5+10;
struct Edge {
int from, to, cap, flow;
Edge(){}// Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
fzhead:fzbody{}
};
//
bool operator<(const Edge& a, const Edge& b) {
return a.from < b.from || (a.from == b.from && a.to < b.to);
}
//
struct ISAP {
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
int p[maxn];
int num[maxn];
//
void add(int from, int to, int cap) {
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
//
bool BFS() {
for(int i=1;i<=n;i++)d[i]=n;///most important .init!!!!!!!!!!!
///这里最好不要用-1或者0x7fffffff等值,否则在统计num的时候可能会出问题
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(t);
vis[t] = 1;
d[t] = 0;
while (!Q.empty()) {
int x = Q.front();
Q.pop();
for (int i = 0; i < sz(G[x]); i++) {
Edge& e = edges[G[x][i] ^ 1];
if (!vis[e.from] && e.cap > e.flow) {
vis[e.from] = 1;
d[e.from] = d[x] + 1;
Q.push(e.from);
}
}
}
return vis[s];
}
//
void init(int n) {
this->n = n;
for (int i = 0; i < n; i++) G[i].clear();
edges.clear();
}
//
int Augment() {
int x = t, a = inf;
while (x != s) {
Edge& e = edges[p[x]];
a = min(a, e.cap - e.flow);
x = edges[p[x]].from;
}
x = t;
while (x != s) {
edges[p[x]].flow += a;
edges[p[x] ^ 1].flow -= a;
x = edges[p[x]].from;
}
return a;
}
//
int maxflow(int s, int t) {
this->s = s;
this->t = t;
int flow = 0;
BFS();
memset(num, 0, sizeof(num));
for (int i = 0; i < n; i++) num[d[i]]++;
///如果d初始为-1等,访问d[-1],d[0x7fffffff]可能会导致未知错误
int x = s;
memset(cur, 0, sizeof(cur));
while (d[s] < n) {
if (x == t) {
flow += Augment();
x = s;
}
int ok = 0;
for (int i = cur[x]; i < sz(G[x]); i++) {
Edge& e = edges[G[x][i]];
if (e.cap > e.flow && d[x] == d[e.to] + 1) {
ok = 1;
p[e.to] = G[x][i];
cur[x] = i;
x = e.to;
break;
}
}
if (!ok) {
int m = n - 1;
for (int i = 0; i < sz(G[x]); i++) {
Edge& e = edges[G[x][i]];
if (e.cap > e.flow) m = min(m, d[e.to]);
}
if (--num[d[x]] == 0) break;
num[d[x] = m + 1]++;
cur[x] = 0;
if (x != s) x = edges[p[x]].from;
}
}
return flow;
}
} sap;
int n,m;
int id(int i, int j){
return (i-1)*m+j;
}
int getval(char *s){
int res=0;
for(int i=1; i<=3; i++){
res*=10;
res+=s[i]-'0';
}
// cout<<res<<endl;
return res;
}
struct point{
int x,y;
int sta;//0:white 1:black 2:have value
int up,left;
}p[maxn];
int main()
{
while(~scanf("%d%d", &n, &m)){
sap.init(maxn);mst(p,0);
char s[20];
int st=0,ed=2e4+10,dv=1e4;
For(i,1,n){
For(j,1,m){
scanf("%s", s+1);
int num=id(i,j);
p[num]={i,j,0,0,0};
if(s[1]=='.')continue;
if(s[4]=='X'){p[num].sta=1;continue;}
if(s[1]!='X')p[num].up=getval(s);
if(s[5]!='X')p[num].left=getval(s+4);
p[num].sta=3;
}
}
For(i,1,n){
For(j,1,m){
int num=id(i,j);
if(p[num].sta==3){
if(p[num].up){
//cout<<num<<endl;
vector<int>in;
int sum=0;
For(k,i+1,n){
if(p[id(k,j)].sta==0)sum++,in.pb(id(k,j));
else break;
}
p[num].up-=sum;
sap.add(st,num,p[num].up);
for(int k=0; k<sz(in); k++)sap.add(num,in[k],8);
}
if(p[num].left){
vector<int>in;
int sum=0;
For(k,j+1,m){
if(p[id(i,k)].sta==0)sum++,in.pb(id(i,k));
else break;
}
p[num].left-=sum;
sap.add(num+dv,ed,p[num].left);
for(int k=0; k<sz(in); k++)sap.add(in[k],num+dv,8);
}
}
}
}
//cout<<"ok1"<<endl;
sap.maxflow(st,ed);
// cout<<"ok2"<<endl;
vector<Edge>&e=sap.edges;
//int &vis=sap.p;
For(i,1,n){
For(j,1,m){
if(p[id(i,j)].sta!=0)printf("_ ");
else {
int num=sap.G[id(i,j)][1];
printf("%d ",e[num].flow+1);
}
}
printf("\n");
}
}
return 0;
}
AC3
Escape HDU - 3605(状态压缩+最大流)
题意:
有n个人,每个人对于m个星球有适应性。
问是否可以所有人达成移民。
思路:
直接建图会tle。
m比较少,可以状态压缩。
把状态相同的人归为一类
AC
#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <cstdio>
#include <algorithm>
#define sz(a) ((int)a.size())
#define pb push_back
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define eb emplace_back
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead EDGE(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int N=100+10;
const int maxn=2000;
const int M=0;
const int inf =0x3f3f3f3f;
struct EDGE{
int from,to,cap,flow;
EDGE(){}
fzhead:fzbody{}
};
struct Dinic{
int n,m,s,t;
vector<EDGE> edges;
vector<int> g[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
///cur就是记录当前循环到了哪一条边。
void init(int n){
this->n = n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
void add(int from, int to, int cap){
// edges.eb(from,to,cap,0);
//edges.eb(to,from,0,0);
edges.pb({from,to,cap,0});
edges.pb({to,from,0,0});
///加边同时,加正向和反向。
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
bool bfs(){
mst(vis,0);
mst(d,0);
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=1;///源点深度为1.
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=0; i<sz(g[x]); i++)
{
EDGE&e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];///当汇点的深度不存在时,说明不存在分层图。
}
int dfs(int x, int a){
///x为当前节点,a为流量。
if(x==t || a==0)return a;///当已经到达汇点,或者流量不存在时,返回。
int flow=0,f;
for(int &i=cur[x]; i<sz(g[x]); i++){
///注意这里的“&”符号,这样i增加同时也能改变cur【x】的值,达到弧优化的目的。
EDGE& e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){///判断并且增广。
e.flow+=f;///加减
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}
return flow;
}
int maxflow(int s, int t){
this->s=s,this->t=t;
int flow=0;
while(bfs()){
///每一次建立分层图后,都要把cur置为每一个点的第一条边
mst(cur,0);
flow+=dfs(s,inf);
}
return flow;
}
} dinic;
int n,m;
int num[2000],lim[20];
int main()
{
while(~scanf("%d%d", &n, &m)){
mst(num,0);
For(i,1,n){
int tmp=0,x;
For(j,1,m){
tmp<<=1;
scanf("%d", &x);
tmp+=x;
}
num[tmp]++;
}
dinic.init(maxn);
int st=1024+m+1,ed=1024+m+2;
int cnt=m;
For(i,1,m)scanf("%d", lim+i),dinic.add(i,ed,lim[i]);
For(i,0,1024-1){
if(!num[i])continue;
cnt++;
dinic.add(st,cnt,num[i]);
for(int j=0; j<m; j++){
if((i>>j)&1)dinic.add(cnt,j+1,num[i]);
}
}
int ans=dinic.maxflow(st,ed);
if(ans==n)printf("YES\n");//printf("%d\n", ans);
else printf("NO\n");
}
return 0;
}
1.2
最大瘤变式–>MincostMaxflow
1.2.1----Going Home POJ - 2195(McMf模板)
题意:
有cnt1个房子,cnt2个人。
人要进到房子里,问怎样走,可以使人的路程和最小。
思路:
裸的最小费用最大流
- 先建点,距离是哈夫曼距离(横坐标的绝对值之差,加上纵坐标的绝对值之差的绝对值)
- 把每个人和房子连边。
- 之后直接跑mxmf即可。
AC
#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define pb push_back
#define sz(a) (int)(a.size())
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead EDGE(int u, int v, int c, int f, int w)
#define fzbody from(u), to(v), cap(c), flow(f), cost(w)
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=1003;
const int maxm=40004;
struct EDGE
{
int from,to,cap,flow,cost;
EDGE(){}
fzhead:fzbody{}
};
struct MXMF
{
int n,m;
vector<EDGE> edges;
vector<int>g[maxn];
int vis[maxn];//判断是否在队中
int d[maxn];//Bellman-Ford
int p[maxn];//上一条弧
int a[maxn];//可改进量
//
void init(int n)
{
this->n=n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
//
void add(int from, int to, int cap, int cost)
{
edges.pb(EDGE(from,to,cap,0,cost));
edges.pb(EDGE(to,from,0,0,-cost));
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
//
bool BellmanFord(int s, int t, int&flow, ll &cost)
{
for(int i=0; i<n; i++)d[i]=INF;
mst(vis,0);
d[s]=0;vis[s]=1;p[s]=0;a[s]=INF;
//
queue<int>q;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
vis[u]=0;
for(int i=0; i<sz(g[u]); i++)
{
EDGE&e=edges[g[u][i]];
if(e.cap>e.flow&&d[e.to]>d[u]+e.cost)
{
d[e.to]=d[u]+e.cost;
p[e.to]=g[u][i];
a[e.to]=min(a[u],e.cap-e.flow);
if(!vis[e.to])
{
q.push(e.to);
vis[e.to]=1;
}
}
}
}
if(d[t]==INF)return false;
flow+=a[t];
cost+=(ll)d[t]*(ll)a[t];
for(int u=t; u!=s; u=edges[p[u]].from)
{
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
}
return true;
}
int MincostMaxflow(int s, int t, ll&cost)
{
int flow=0;cost=0;
while(BellmanFord(s,t,flow,cost));
return flow;
}
}mxmf;
struct point
{
int x,y;
}house[maxn],men[maxn];
int main()
{
int n,m;
char s[200];
while(scanf("%d%d", &n,&m)&&(n&&m))
{
mxmf.init(maxn);
int cnt1,cnt2;
cnt1=cnt2=0;//cnt1-house, cnt2-men
for(int i=0; i<n; i++)
{
scanf("%s", s);
for(int j=0; j<m; j++)
{
if(s[j]=='H')house[++cnt1].x=i,house[cnt1].y=j;
if(s[j]=='m')men[++cnt2].x=i,men[cnt2].y=j;
}
}
int st=0,ed=cnt1+cnt2+1;
for(int i=1; i<=cnt2; i++)
{
for(int j=1; j<=cnt1; j++)
{
int w=abs(men[i].x-house[j].x)+abs(men[i].y-house[j].y);
mxmf.add(i,cnt2+j,1,w);
}
}
for(int i=1; i<=cnt2; i++)
{
mxmf.add(st,i,1,0);
mxmf.add(cnt2+i,ed,1,0);
}
ll cost=0,flow=0;
mxmf.MincostMaxflow(st,ed,cost);
printf("%lld\n",cost);
}
return 0;
}
1.2.2----Minimum Cost POJ - 2516(mcmf,跑k次)
题意:
有n个批发点supply place, 和m个shopkeeper店主。
而且有k种产品。(运费不同)
问怎样分配运费,可以使得总费用最小。
思路:
- 直接建图的话,50x50 x 50x50个点,有1e6,所以
考虑跑k次
。
反思:
建点和连边时,最好画一个图,避免连错。(连边时,思路可以更清晰)
AC
#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define pb push_back
#define sz(a) (int)(a.size())
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead Edge(int u, int v, int c, int f, int w)
#define fzbody from(u), to(v), cap(c), flow(f), cost(w)
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=3000;
const int maxm=400004;
struct Edge
{
int from, to, cap, flow, cost;
Edge(){}
fzhead:fzbody{}
};
struct MCMF
{
int n,m;
vector<Edge>edges;
vector<int> g[maxn];
int vis[maxn];
int d[maxn];
int p[maxn];
int a[maxn];
//
void init(int n)
{
this->n=n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
//
void add(int from, int to, int cap, int cost)
{
edges.pb(Edge(from,to,cap,0,cost));
edges.pb(Edge(to,from,0,0,-cost));
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
//
bool BellmanFord(int s,int t, int&flow, ll&cost)
{
for(int i=0 ; i<n; i++)d[i]=INF;
mst(vis,0);
d[s]=0;vis[s]=1;p[s]=0;a[s]=INF;
//
queue<int>q;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
vis[u]=0;
for(int i=0; i<sz(g[u]); i++)
{
Edge& e=edges[g[u][i]];
if(e.cap>e.flow&& d[e.to]>d[u]+e.cost)
{
d[e.to]=d[u]+e.cost;
p[e.to]=g[u][i];
a[e.to]=min(a[u],e.cap-e.flow);
if(!vis[e.to])
{
q.push(e.to);
vis[e.to]=1;
}
}
}
}
if(d[t]==INF)return false;
flow+=a[t];
cost+=(ll)d[t]*(ll)a[t];
for(int u=t; u!=s; u=edges[p[u]].from)
{
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
}
return true;
}
int MincostMaxflow(int s,int t, ll& cost)
{
int flow=0;cost=0;
while(BellmanFord(s,t,flow,cost));
return flow;
}
}mcmf;
int n,m,k;
int need[100][100],have[100][100];
int main()
{
while(scanf("%d%d%d", &n,&m,&k)&&n&&m&&k)
{
mcmf.init(maxn);
int flag=1,s=0,e=n+m+1;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=k; j++)scanf("%d", need[i]+j);
}
for(int i=1; i<=m; i++)
{
for(int j=1; j<=k; j++)scanf("%d", have[i]+j);
}
ll cost,ans=0,flow;
for(int i=1; i<=k; i++)
{
mcmf.init(maxn);
for(int p=1; p<=n; p++)
{
for(int q=1; q<=m; q++)
{
int w;
scanf("%d", &w);
mcmf.add(q,m+p,INF,w);
}
}
if(!flag)continue;
for(int p=1; p<=m; p++)mcmf.add(s,p,have[p][i],0);
ll sum=0;
for(int p=1; p<=n; p++)
{
mcmf.add(p+m,e,need[p][i],0);
sum+=need[p][i];
}
flow=cost=0;
flow=mcmf.MincostMaxflow(s,e,cost);
// cout<<"k== "<<k<<' '<<sum<<' '<<cost<<endl;
if(flow!=sum)flag=0;
else ans+=cost;
}
if(flag)printf("%lld\n", ans);
else printf("-1\n");
}
return 0;
}
1.3
最大瘤变式–>最小鸽
1.3.1----Control HDU - 4289(最小割&&割点,加拆点)
题意:
有一个不法分子,会从 s s s出发到 d e de de.为了抓到他,要在城市设置sa(特工),问最少需要设置几个特工。
思路&&反思:
问题就是最小割。增广后,不能再增广。
- 最小割一般有联系的边,设置为 I N F INF INF
- 一个点的花费,就拆点。
- 注意拆点后
首尾相连
.
图片来自传送门
AC
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define pb push_back
#define sz(a) (int)(a.size())
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxm=400+10+4e4+10;
const int maxn=400+10;
const int inf=0x3f3f3f3f;
struct Edge{
int from, to, cap, flow;
Edge(){}
fzhead:fzbody{}
};
struct Dinic{
int n,m,s,t;
vector<Edge>edges;
vector<int>g[maxn];
int d[maxn];
bool vis[maxn];
int cur[maxn];
void init(int n){
this->n=n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
void add(int from, int to, int cap){
edges.pb({from,to,cap,0});
edges.pb({to,from,0,0});
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
bool bfs(){
mst(vis,0);mst(d,0);
queue<int>q;
q.push(s);
vis[s]=1;
d[s]=0;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0; i<sz(g[x]); i++){
Edge&e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x, int a){
if(x==t||a==0)return a;
int flow=0,f;
for(int &i=cur[x]; i<sz(g[x]); i++){
Edge&e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
e.flow+=f;
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}
return flow;
}
int maxflow(int s, int t){
this->s=s,this->t=t;
int flow=0;
while(bfs()){
mst(cur,0);
flow+=dfs(s,inf);
}
return flow;
}
} dinic;
int n,m,s,e;
int main()
{
while(~scanf("%d%d", &n, &m)){
dinic.init(maxn);
scanf("%d%d", &s, &e);
int w,u,v;
int st=0,ed=401;
dinic.add(st,s,inf);
dinic.add(e+n,ed,inf);
For(i,1,n){
scanf("%d",&w);
dinic.add(i,i+n,w);
dinic.add(n+i,i,w);
}
For(i,1,m){
scanf("%d%d", &u,&v);
dinic.add(u+n,v,inf);
dinic.add(v+n,u,inf);
}
printf("%d\n",dinic.maxflow(st,ed));
}
return 0;
}
Sabotage UVA - 10480(割边)
题意:
给你一个网络图。起点和终点,要求你割掉最小费用的边,使s和d不联通。
思路:
- 跑一遍最大流,
- 残余网络里,把与s联通的点找出来,标记为1。(
剩下的点就与t联通
) - 那么答案就是:遍历输入的每一条边,假如两点vis不同,那么就输出。
AC
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>
#define mp make_pair
#define sz(a) (int)(a.size())
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead Edge(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
typedef long long ll;
typedef pair<int,int>pa;
const int maxn=200+10;
const int inf=0x3f3f3f3f;
struct Edge{
int from, to;
ll cap,flow;
Edge(){}
fzhead:fzbody{}
};
struct Dinic{
int n, m,s,t;
vector<Edge>edges;
vector<int>g[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n){
this->n=n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
void add(int from, int to, int cap){
edges.pb({from,to,cap,0});
edges.pb({to,from,0,0});
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
bool bfs(){
mst(vis,0);mst(d,0);
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0; i<sz(g[x]); i++){
Edge&e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];
}
ll dfs(int x,ll a){
if(x==t||a==0)return a;
ll flow=0,f;
for(int&i=cur[x]; i<sz(g[x]); i++){
Edge&e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
e.flow+=f;
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}
return flow;
}
ll maxflow(int s,int t){
this->s=s,this->t=t;
ll flow=0;
while(bfs()){
mst(cur,0);
flow+=dfs(s,inf);
}
return flow;
}
}dinic;
int vis[maxn];
void col(int x){
vis[x]=1;
vector<int>&g=dinic.g[x];
vector<Edge>&edges=dinic.edges;
for(int i=0; i<sz(g); i++){
Edge&e=edges[g[i]];
//cout<<e.to<<' ';
if(e.cap>e.flow&&!vis[e.to])col(e.to);
}
}
struct point{
int u,v;
}p[maxn<<3];
int main()
{
//cout << "Hello world!" << endl;
int n,m;
while(scanf("%d%d", &n,&m)&&(n||m)){
dinic.init(maxn);mst(vis,0);
int u,v;
ll w;
For(i,1,m){
scanf("%d%d%lld", &u, &v, &w);
dinic.add(u,v,w);
dinic.add(v,u,w);
p[i]={u,v};
}
// cout<<"ok"<<endl;
//printf("%d\n\n",dinic.maxflow(s,ed));
dinic.maxflow(1,2);//<<endl;
// cout<<"ok"<<endl;
col(1);
for(int i=1; i<=m; i++){
int u=p[i].u,v=p[i].v;
if((vis[u]&&vis[v]==0)||(vis[v]&&vis[u]==0))printf("%d %d\n",u, v);
}
printf("\n");
}
return 0;
}
/*
5 8
1 4 30
1 3 70
5 3 20
4 3 5
4 5 15
5 2 10
3 2 25
2 4 50
5 8
1 4 30
1 3 70
5 3 20
4 3 5
4 5 15
5 2 10
3 2 25
2 4 50
0 0
*/