不讲入门!(以后有空可能会写?)
网络流模板题ditch
题目描述
在农夫约翰的农场上,每逢下雨,Bessie最喜欢的三叶草地就积聚了一潭水。这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间。因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪)。作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量。 农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小溪的一张网)。需要注意的是,有些时候从一处到另一处不只有一条排水沟。 根据这些信息,计算从水潭排水到小溪的最大流量。对于给出的每条排水沟,雨水只能沿着一个方向流动,注意可能会出现雨水环形流动的情形。
输入格式
第1行: 两个用空格分开的整数N (0 <= N <= 200) 和 M (2 <= M <= 200)。N是农夫John已经挖好的排水沟的数量,M是排水沟交叉点的数量。交点1是水潭,交点M是小溪。 第二行到第N+1行: 每行有三个整数,Si, Ei, 和 Ci。Si 和 Ei (1 <= Si, Ei <= M) 指明排水沟两端的交点,雨水从Si 流向Ei。Ci (0 <= Ci <= 10,000,000)是这条排水沟的最大容量。
输出格式
输出一个整数,即排水的最大流量。
input
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
output
50
数据规模与约定
时间限制:1s 空间限制:256MB
用最裸的退流方式。
#include<bits/stdc++.h>
using namespace std;
const long long oo=165430000;
bool check,vis[11000];
long long n,m,lazy,ans,linkk[11000],t;
struct node
{
long long n,y,v;
}e[110000];
long long read()
{
bool flag=true;
long long num=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false;
for(;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
if(flag) return num;
else return -num;
}
void init()
{
m=read();n=read();
int aa,bb,cc;
t=1;
for(int i=1;i<=m;++i)
{
aa=read();bb=read();cc=read();
e[++t].n=linkk[aa];
e[t].y=bb;
e[t].v=cc;
linkk[aa]=t;
e[++t].n=linkk[bb];
e[t].y=aa;
e[t].v=0;
linkk[bb]=t;
}
}
void dfs(int x,long long point)
{
vis[x]=true;
if(x==n)
{
ans+=point;
check=true;
lazy=point;
return;
}
for(int i=linkk[x];i;i=e[i].n)
if(!vis[e[i].y]&&e[i].v>0)
{
dfs(e[i].y,min(point,e[i].v));
if(check)
{
e[i].v-=lazy;
e[i^1].v+=lazy;
return;
}
}
return;
}
int main()
{
init();
check=true;
while(check)
{
check=false;
memset(vis,0,sizeof(vis));
dfs(1,oo);
}
printf("%lld",ans);
return 0;
}
dinic
将第一题的数据范围扩大到N (0 <= N <= 500000) 和 M (2 <= M <= 1000)
dinic法做网络流(模板)
#include<bits/stdc++.h>
using namespace std;
const long long oo=165430000;
bool check;
long long n,m,lazy,ans,linkk[1100],t,deep[1100],head,tail,q[1100];
struct node
{
long long n,y,v;
}e[1100000];
long long read()
{
bool flag=true;
long long num=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false;
for(;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
if(flag) return num;
else return -num;
}
void init()
{
m=read();n=read();
int aa,bb,cc;
t=1;
for(int i=1;i<=m;++i)
{
aa=read();bb=read();cc=read();
e[++t].n=linkk[aa];
e[t].y=bb;
e[t].v=cc;
linkk[aa]=t;
e[++t].n=linkk[bb];
e[t].y=aa;
e[t].v=0;
linkk[bb]=t;
}
}
int dfs(int x,long long lazy)
{
if(x==n)return lazy;
int nowlazy=0;
int d=0;
for(int i=linkk[x];i&&nowlazy<lazy;i=e[i].n)
{
int v=e[i].y;
if(deep[v]==deep[x]+1&&e[i].v>0)
if(d=dfs(v,min(e[i].v,lazy-nowlazy)))
{
nowlazy+=d;
e[i].v-=d;
e[i^1].v+=d;
}
}
if(nowlazy==0) deep[x]=-1;
return nowlazy;
}
void bfs()
{
memset(deep,-1,sizeof(deep));
deep[1]=0;head=tail=1;
q[1]=1;
while(head<=tail)
{
int v=q[head];
for(int i=linkk[v];i;i=e[i].n)
if(deep[e[i].y]==-1&&e[i].v>0) deep[e[i].y]=deep[v]+1,q[++tail]=e[i].y;
head++;
}
if(deep[n]!=-1) check=true;
return;
}
int main()
{
init();
check=true;
while(check)
{
int d=0;check=false;
bfs();
if(!check) break;
while(d=dfs(1,oo)) ans+=d;
}
printf("%lld",ans);
return 0;
}
奶牛的聚会
N(3<=N<=200)头奶牛要办一个新年晚会。每头牛都会烧几道菜。一共有D(5<=D<=100)道不同的菜肴。每道菜都可以用一个1到D之间的数来表示。 晚会的主办者希望能尽量多的菜肴被带到晚会,但是每道菜的数目又给出了限制。每头奶牛可以带K(1<=K<=5)道菜,但是必须是各不相同的(例如,一头牛不能带三块馅饼,但是可以带上一块馅饼,一份面包,和一些美味的桔子酱苜蓿)。那么,究竟有多少菜可以被带来晚会呢?
输入格式
第一行包括三个整数N,K和D。 第二行有D个非负整数,表示每种菜可以带到晚会上的数目限制。 第三行到第N+2行,每行包括一个整数Z,表示一头牛可以准备的菜的道数;之后Z个整数,表示菜的标号,首先是第一种菜,然后是第二种菜,以此类推。
输出格式
仅一行一个整数,表示可以带到晚会上的最多的菜的数目。
input
4 3 5
2 2 2 2 3
4 1 2 3 4
4 2 3 4 5
3 1 2 4
3 1 2 3
output
9
数据规模与约定
时间限制:1s 空间限制:256MB
网络流入门….
#include<bits/stdc++.h>
using namespace std;
const long long oo=165430000;
bool check,vis[500];
long long n,k,d,lazy,ans,linkk[500],t,f[300];
const int endd=301;
struct node
{
long long n,y,v;
}e[110000];
long long read()
{
bool flag=true;
long long num=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false;
for(;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
if(flag) return num;
else return -num;
}
void init()
{
n=read();k=read();d=read();
int xx,yy;
t=1;
for(int i=1;i<=d;++i)
{
int v=i+200;
xx=read();
e[++t].n=linkk[v];
e[t].v=xx;
e[t].y=endd;
linkk[v]=t;
e[++t].n=linkk[endd];
e[t].v=0;
e[t].y=v;
linkk[endd]=t;
}
for(int i=1;i<=n;++i)//1~200牛
{
xx=read();
for(int j=1;j<=xx;++j)//201~300 菜
{
yy=read();//菜
int v=yy+200;
e[++t].n=linkk[i];
e[t].v=1;
e[t].y=v;
linkk[i]=t;
e[++t].n=linkk[v];
e[t].v=0;
e[t].y=i;
linkk[v]=t;
}
}
for(int i=1;i<=n;++i)
{
e[++t].n=linkk[0];
e[t].v=k;
e[t].y=i;
linkk[0]=t;
e[++t].n=linkk[i];
e[t].v=0;
e[t].y=0;
linkk[i]=t;
}
}
void dfs(int x,long long point)
{
vis[x]=true;
if(x==endd)
{
ans+=point;
check=true;
lazy=point;
return;
}
for(int i=linkk[x];i;i=e[i].n)
if(!vis[e[i].y]&&e[i].v>0)
{
dfs(e[i].y,min(point,e[i].v));
if(check)
{
e[i].v-=lazy;
e[i^1].v+=lazy;
return;
}
}
return;
}
int main()
{
init();
check=true;
while(check)
{
check=false;
memset(vis,0,sizeof(vis));
dfs(0,oo);
}
printf("%lld",ans);
return 0;
}
晚餐
农夫JOHN为牛们做了很好的食品,但是牛吃饭很挑食. 每一头牛只喜欢吃一些食品和饮料而别的一概不吃.虽然他不一定能把所有牛喂饱,他还是想让尽可能多的牛吃到他们喜欢的食品和饮料.
农夫JOHN做了F (1 <= F <= 100) 种食品并准备了D (1 <= D <= 100) 种饮料. 他的N (1 <= N <= 100)头牛都以决定了是否愿意吃某种食物和喝某种饮料. 农夫JOHN想给每一头牛一种食品和一种饮料,使得尽可能多的牛得到喜欢的食物和饮料.
每一件食物和饮料只能由一头牛来用. 例如如果食物2被一头牛吃掉了,没有别的牛能吃食物2.
输入格式
第一行: 三个数: N, F, 和 D
第2..N+1行: 每一行由两个数开始F_i 和 D_i, 分别是第i 头牛可以吃的食品数和可以喝的饮料数.下F_i个整数是第i头牛可以吃的食品号,再下面的D_i个整数是第i头牛可以喝的饮料号码.
输出格式
第一行: 一个整数,最多可以喂饱的牛数.
input
4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3
输入解释:
牛 1: 食品从 {1,2}, 饮料从 {1,3} 中选
牛 2: 食品从 {2,3}, 饮料从 {1,2} 中选
牛 3: 食品从 {1,3}, 饮料从 {1,2} 中选
牛 4: 食品从 {1,3}, 饮料从 {3} 中选
output
3
输出解释:
一个方案是:
Cow 1: 不吃
Cow 2: 食品 #2, 饮料 #2
Cow 3: 食品 #1, 饮料 #1
Cow 4: 食品 #3, 饮料 #3
用鸽笼定理可以推出没有更好的解 (一共只有3总食品和饮料).当然,别的数据会更难.
数据规模与约定
时间限制:1s 空间限制:256MB
还是入门题
#include<bits/stdc++.h>
using namespace std;
const long long oo=165430000;
bool check,vis[500];
long long n,F,d,lazy,ans,linkk[500],t,f[300];
const int endd=401;
struct node
{
long long n,y,v;
}e[10000];
long long read()
{
bool flag=true;
long long num=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false;
for(;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
if(flag) return num;
else return -num;
}
void init()
{
n=read();F=read();d=read();
int xx,yy,zz;
t=1;
for(int i=1;i<=n;++i)
{
xx=read();yy=read();
for(int j=1;j<=xx;++j) //牛和食物
{ //1~100 牛 101~200 牛2 201~300食物 301~400饮料
zz=read(); //s~食物~牛~牛2~饮料~T
e[++t].n=linkk[zz+200];
e[t].y=i;
e[t].v=1;
linkk[zz+200]=t;
e[++t].n=linkk[i];
e[t].y=zz+200;
e[t].v=0;
linkk[i]=t;
}
for(int j=1;j<=yy;++j)//牛2~饮料
{
zz=read();
e[++t].n=linkk[i+100];
e[t].y=zz+300;
e[t].v=1;
linkk[i+100]=t;
e[++t].n=linkk[zz+300];
e[t].y=i+100;
e[t].v=0;
linkk[zz+300]=t;
}
}
for(int i=1;i<=F;++i) //S~食物
{
e[++t].n=linkk[0];
e[t].y=i+200;
e[t].v=1;
linkk[0]=t;
e[++t].n=linkk[i+200];
e[t].y=0;
e[t].v=0;
linkk[i+200]=t;
}
for(int i=1;i<=n;++i) //牛~牛
{
e[++t].n=linkk[i];
e[t].y=i+100;
e[t].v=1;
linkk[i]=t;
e[++t].n=linkk[i+100];
e[t].y=i;
e[t].v=0;
linkk[i+100]=t;
}
for(int i=1;i<=d;++i)//饮料~T
{
e[++t].n=linkk[300+i];
e[t].y=endd;
e[t].v=1;
linkk[300+i]=t;
e[++t].n=linkk[endd];
e[t].y=300+i;
e[t].v=0;
linkk[endd]=t;
}
return;
}
void dfs(int x,long long point)
{
vis[x]=true;
if(x==endd)
{
check=true;
lazy=point;
ans+=point;
return;
}
for(int i=linkk[x];i;i=e[i].n)
if(!vis[e[i].y]&&e[i].v>0)
{
dfs(e[i].y,min(point,e[i].v));
if(check)
{
e[i].v-=lazy;
e[i^1].v+=lazy;
return;
}
}
return;
}
int main()
{
init();
check=true;
while(check)
{
check=false;
memset(vis,0,sizeof(vis));
dfs(0,oo);
}
printf("%lld",ans);
return 0;
}
养猪\
尼克在一家养猪场工作,这家养猪场共有M间锁起来的猪舍,由于猪舍的钥匙都给了客户,所以尼克没有办法打开这些猪舍,客户们从早上开始一个接一个来购买生猪,他们到达后首先用手中的钥匙打开他所能打开的全部猪舍,然后从中选取他要买的生猪,尼克可以在此期间将打开的猪舍中的猪调整到其它开着的猪舍中,每个猪舍能存放的猪的数量是没有任何限制的。买完猪后客户会将他打开的猪舍关上。
好在尼克事先知道每位客户手中有哪些钥匙,要买多少猪,以及客户到来的先后次序。请你写一个程序,帮助尼克求出最多能卖出多少头生猪。
输入格式
输入文件的第一行包含两个整数M和N,1≤M≤1000,1≤N≤100,M为猪舍的数量,N为客户人数,猪舍的编号为1到M,客户的编号为1到N。
输入文件第二行包含M个空格隔开的整数,依次表示每个猪舍中的生猪数量,每个整数大于等于0,且小于等于1000。
接下来的N行每行表示一位客户的购买信息,第I个客户的购买信息位于第I+2行,
其格式如下:
A K1 K2……KA B
它表示该客户共有A把钥匙,钥匙编号依次为K1 K2……KA,且K1< K2<……< KA,B为该客户要买的生猪的头数。
输出格式
输出文件仅有一行包含一个整数,表示尼克最多能卖出的生猪的头数。
input
3 3
3 1 10
2 1 2 2
2 1 3 3
1 2 6
output
7
数据规模与约定
1s
poj 1149
时间限制:1s
空间限制:256MB
有一点点思维难度。
同一个猪圈前面能打开的客户要向后面能打开的连边。
#include<bits/stdc++.h>
using namespace std;
const long long oo=165430000;
bool check,vis[1500];
long long n,m,lazy,ans,linkk[1500],t,app[1500];
const int endd=1102;
struct node
{
long long n,y,v;
}e[10000];
long long read()
{
bool flag=true;
long long num=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false;
for(;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
if(flag) return num;
else return -num;
}
void insert(int xx,int yy,int zz)
{
e[++t].n=linkk[xx];
e[t].y=yy;
e[t].v=zz;
linkk[xx]=t;
e[++t].n=linkk[yy];
e[t].y=xx;
e[t].v=0;
linkk[yy]=t;
}
void init()
{
m=read();n=read();
t=1;
memset(app,0,sizeof(app));
for(int i=1;i<=m;++i)
{
int xx=read();
insert(0,i,xx);
}
for(int i=1;i<=n;++i)
{
int xx=read();
for(int j=1;j<=xx;++j)
{
int yy=read();
if(app[yy]==0) app[yy]=1000+i,insert(yy,1000+i,oo);
else insert(app[yy],1000+i,oo);
}
int zz=read();
insert(1000+i,endd,zz);
}
// for(int i=1;i<=n-1;++i)
// insert(1000+i,1001+i,oo);
return;
}
void dfs(int x,long long point)
{
vis[x]=true;
if(x==endd)
{
ans+=point;
check=true;
lazy=point;
return;
}
for(int i=linkk[x];i;i=e[i].n)
if(!vis[e[i].y]&&e[i].v>0)
{
dfs(e[i].y,min(point,e[i].v));
if(check)
{
e[i].v-=lazy;
e[i^1].v+=lazy;
return;
}
}
return;
}
int main()
{
init();
check=true;
while(check)
{
check=false;
memset(vis,0,sizeof(vis));
dfs(0,oo);
}
printf("%lld",ans);
return 0;
}
[最小割模板]巡逻
题目描述
FJ有个农场,其中有n块土地,由m条边连起来。FJ的养牛场在土地1,在土地n有个新开张的雪糕店。Bessie经常偷偷溜到雪糕店,当Bessie去的时候,FJ就要跟上她。但是Bessie很聪明,她在从雪糕店返回时不会经过去雪糕店时经过的农场,因此FJ总是抓不住Bessie。 为了防止Bessie生病,FJ决定把一些诚实的狗放在一些土地(1和n除外)上,使Bessie无法在满足每块土地最多只经过一次的条件的情况下,从养牛场溜到雪糕店然后又溜回养牛场。 求出FJ最少要放多少只狗。数据保证1和n间没有直接的连边。
输入格式
Line 1: Two integers: N and M.
Lines 2..M+1: Each line contains two integers A and B that describea trail joining fields A and B. It is possible to travelalong this trail both ways. No trail will appear twice.
输出格式
Line 1: A single integer that tells how many fields FJ should guard.
input
6 7
1 2
2 6
1 3
3 4
3 5
4 6
5 6
output
1
OUTPUT DETAILS:
FJ can guard field 2 (for example). FJ could guard both fields 4 and
5, but that would require more dogs.
数据规模与约定
数据范围:n<=1000,m<=10000。
时间限制:1s
空间限制:256MB
一道最小割的模板题
显而易见的,我们可以想到把第i个点拆成i和i+n,把两个点连起来,权值为1。那么最小割问题就转化为最大流了。
这道题的问题就是两个点之间的边到底怎么连。
i为入点,i+n为出点。
那么所有由出点到入点的边权值为0。
由入点到出点的边权值为1(任意正整数都行)。
所以对于两个点a,b
我们只要insert(a+n,b,1),(b+n,a,1) 那么只要套一下dinic模板就行了。
#include<bits/stdc++.h>
using namespace std;
const int oo=165430000;
bool check;
int n,m,lazy,ans,linkk[21000],t,deep[21000],head,tail,q[21000];
struct node
{
int n,y,v;
}e[1100000];
int read()
{
bool flag=true;
int num=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false;
for(;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
if(flag) return num;
else return -num;
}
void insert(int aa,int bb,int cc)
{
e[++t].n=linkk[aa];
e[t].y=bb;
e[t].v=cc;
linkk[aa]=t;
e[++t].n=linkk[bb];
e[t].y=aa;
e[t].v=0;
linkk[bb]=t;
return;
}
void init()
{
n=read();m=read();
int aa,bb;
t=1;
for(int i=1;i<=m;++i) //点①
{
aa=read();bb=read();
if(aa>bb) swap(aa,bb);
if(aa!=1)
insert(aa+n,bb,1),insert(bb+n,aa,1);
else
insert(1,bb,1),insert(bb,1,1);
}
for(int i=2;i<=n-1;++i)
insert(i,i+n,1);
return;
}
int dfs(int x,int lazy)
{
if(x==n)return lazy;
int nowlazy=0;
int d=0;
for(int i=linkk[x];i&&nowlazy<lazy;i=e[i].n)
{
int v=e[i].y;
if(deep[v]==deep[x]+1&&e[i].v>0)
if(d=dfs(v,min(e[i].v,lazy-nowlazy)))
{
nowlazy+=d;
e[i].v-=d;
e[i^1].v+=d;
}
}
if(nowlazy==0) deep[x]=-1;
return nowlazy;
}
void bfs()
{
memset(deep,-1,sizeof(deep));
deep[1]=0;head=tail=1;
q[1]=1;
while(head<=tail)
{
int v=q[head];
for(int i=linkk[v];i;i=e[i].n)
if(deep[e[i].y]==-1&&e[i].v>0) deep[e[i].y]=deep[v]+1,q[++tail]=e[i].y;
head++;
}
if(deep[n]!=-1) check=true;
return;
}
int main()
{
init();
check=true;
while(check)
{
int d=0;check=false;
bfs();
if(!check) break;
while(d=dfs(1,oo)) ans+=d;
}
if(ans!=0)
printf("%d",ans-1);
else printf("0");
return 0;
}