这几天做了些网络流的题,在此复习一下:
bzoj 1066 蜥蜴
http://www.lydsy.com/JudgeOnline/problem.php?id=1066
最大流
先拆点,对于每个石柱i,拆成in(i),ou(i)两点,连一条容量height[i]的边,能跳出去的向T连容量INF的边,然后对于每条蜥蜴,向能够到的石柱连一条容量INF的边表示跳跃,S向每条蜥蜴连容量1的边,跑最大流就解决了。。。。
注意距离的含义~~~直线距离。。。被一神犇坑了。。。
贴代码:
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<iostream>
#include<queue>
#define INF 0x3f3f3f
#define MAXN 50
using namespace std;
int s,t,ans;
char mapp[MAXN][MAXN];
bool can[MAXN][MAXN];
int n,m,d,eid;
int hight[MAXN][MAXN];
int g[MAXN*MAXN*MAXN];
inline int IN(int x,int y){return (x*m+y)*2+1;}
inline int OU(int x,int y){return (x*m+y)*2+2;}
struct Edge{
int v, f, nxt;
Edge() {};
Edge(int a,int b,int c)
{
v=b;
nxt=g[a];
f=c;
}
}e[MAXN*MAXN*MAXN];
inline void addedge(int a,int b,int c)
{
e[++eid]=Edge(a,b,c);
g[a]=eid;
e[++eid]=Edge(b,a,0);
g[b]=eid;
}
queue<int >q;
int dis[MAXN*MAXN*MAXN];
bool vis[MAXN*MAXN*MAXN];
inline void bfs()
{
memset(dis,INF,sizeof(dis));
memset(vis,false,sizeof(vis));
while(!q.empty())
q.pop();
q.push(s);
vis[s]=true;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&!vis[e[i].v])
{
vis[e[i].v]=true;
q.push(e[i].v);dis[e[i].v]=dis[u]+1;
}
}
}
inline int fdis(int a,int b,int c,int d)
{
return (a-c)*(a-c)+(b-d)*(b-d);
}
inline int dfs(int u,int delta)
{
if(u==t)
return delta;
else
{
int ret=0;
for(int i=g[u];delta&&i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]==dis[u]+1)
{
int dd=dfs(e[i].v,min(e[i].f,delta));
e[i].f-=dd;
e[i^1].f+=dd;
ret+=dd;
delta-=dd;
}
return ret;
}
}
inline int maxflow()
{
int ret=0;
while(true)
{
bfs();
if(!vis[t])return ret;
ret+=dfs(s,INF);
}
}
inline void init()
{
eid=1;
memset(g,0,sizeof(g));
scanf("%d%d%d",&n,&m,&d);
s=OU(n-1,m-1)+1; t=OU(n-1,m-1)+2;
for(int i=1;i<=n;i++)
{
scanf("%s",mapp[i]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
hight[i][j]=mapp[i][j-1]-'0';
}
for(int i=1;i<=n;i++)
{
scanf("%s",mapp[i]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(mapp[i][j-1]=='L')
{
ans++;
addedge(s,IN(i-1,j-1),1);
}
if(hight[i][j])
{
addedge(IN(i-1,j-1),OU(i-1,j-1),hight[i][j]);
if(i<=d||i>n-d||j<=d||j>m-d)
addedge(OU(i-1,j-1),t,INF);
for(int x=1;x<=n;x++)
for(int y=1;y<=m;y++)
{
if(i==x && j==y) continue;
if(!hight[x][y]) continue;
if(fdis(i,j,x,y)<=d*d)
{
addedge(OU(i-1,j-1),IN(x-1,y-1),INF);
}
}
}
}
}
int main()
{
init();
printf("%d\n",ans-maxflow());
return 0;
}
bzoj 1070 修车
http://www.lydsy.com/JudgeOnline/problem.php?id=1070
费用流
先拆点,把每个技术人员分别拆成N个点。
S向每个技术人员连容量1费用0的边,每个车向T连容量1费用0的边
考虑第i个技术人员在修第j辆车对于前面的车等候时间没影响,但对后面的有,所以i向j连一条容量1费用(n-k+1)*time[i][j]的边,跑费用流;
贴代码:
<span style="font-family:Microsoft YaHei;font-size:18px;">#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define N 10000
#define M 200000
#define INF 1e9
using namespace std;
int head[N],next[M],to[M],len[M],pr[M];
int n,m,cnt,S,T,mlen;
int tim[1000][1000];
int dis[N],pre[N],q[M];
bool vis[N];
inline void add(int u,int v,int r,int w)
{
to[cnt]=v; len[cnt]=r; pr[cnt]=w; next[cnt]=head[u]; head[u]=cnt++;
to[cnt]=u; len[cnt]=0; pr[cnt]=-w; next[cnt]=head[v]; head[v]=cnt++;
}
inline void read()
{
memset(head,-1,sizeof head); cnt=0;
scanf("%d%d",&m,&n);
S=0; T=n+n*m+1;
for(int i=1,a;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&tim[i][j]);
for(int i=1;i<=n;i++) add(S,i,1,0);
for(int i=n+n*m;i>=n+1;i--) add(i,T,1,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=n;k++)
add(i,j*n+k,1,(n-k+1)*tim[i][j]);
}
inline bool spfa()
{
memset(pre,-1,sizeof pre);
memset(dis,0x3f,sizeof dis);
int h=1,t=2,sta;
q[1]=S; dis[S]=0; vis[S]=true;
while(h<t)
{
sta=q[h++]; vis[sta]=false;
for(int i=head[sta];~i;i=next[i])
if(len[i]&&dis[to[i]]>dis[sta]+pr[i])
{
dis[to[i]]=dis[sta]+pr[i];
pre[to[i]]=i;
if(!vis[to[i]]) q[t++]=to[i],vis[to[i]]=true;
}
}
return pre[T]!=-1;
}
inline void updata()
{
mlen=INF;
for(int i=pre[T];~i;i=pre[to[i^1]])
mlen=min(mlen,len[i]);
for(int i=pre[T];~i;i=pre[to[i^1]])
len[i]-=mlen,len[i^1]+=mlen;
}
inline void go()
{
int ans=0;
while(spfa()) updata(),ans+=dis[T]*mlen;
printf("%.2lf\n",double(ans)/n);
}
int main()
{
read();
go();
return 0;
}</span>
bzoj 1877 晨跑
http://www.lydsy.com/JudgeOnline/problem.php?id=1877
费用流
算是比较水的了,拆点,
对于i点in(i)向ou(i)连容量1费用0边(i==1||i==n 容量为INF)
S向in(1)连容量INF,ou(n)向T连容量INF费用0,ou(i)向in(j)连容量1费用len[i][j]边
第一问就是增广次数,二问最小费用
贴代码:
#include<cstdio>
#include<cstring>
#include<queue>
#define MAXN 20010
#define M 600
#define INF 0x3f3f3f
using namespace std;
struct Edge{
Edge(){};
Edge(int a,int b,int c,int d)
{
v=a; f=b; w=c; nxt=d;
}
int v,f,w,nxt;
}e[MAXN<<2];
int g[MAXN<<2];
int s,t,n,m,eid;
inline int IN(int i)
{
return i+1;
}
inline int OU(int i)
{
return i+1+n;
}
int tot,ans;
inline void addedge(int u,int v,int f,int w)
{
e[++eid]=Edge(v,f,w,g[u]);
g[u]=eid;
e[++eid]=Edge(u,0,-w,g[v]);
g[v]=eid;
}
int dis[M];
bool vis[M];
int pree[M],prev[M];
inline bool findPath()
{
queue<int > q;
q.push(s);
memset(dis,INF ,sizeof(dis));
dis[s]=0;
//vis[s]=true;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[s]=true;
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]>dis[u]+e[i].w)
{
dis[e[i].v]=dis[u]+e[i].w;
pree[e[i].v]=i;
prev[e[i].v]=u;
if(!vis[e[i].v])
{
vis[e[i].v]=true;
q.push(e[i].v);
}
}
vis[u]=false;
}
return (dis[t]<INF ) ? true : false;
}
inline int augment()
{
int u=t;int delta=INF;
while(u!=s)
{
delta=min(delta,e[pree[u]].f);
u=prev[u];
}
u=t;
while(u!=s)
{
e[pree[u]].f-=delta;
e[pree[u]^1].f+=delta;
u=prev[u];
}
tot+=delta;
return dis[t]*delta;
}
inline void minflow()
{
ans=0;
while(findPath())
{
//tot++;
ans+=augment();
}
return ;
}
inline void init()
{
eid=1;
scanf("%d%d",&n,&m);
for(int i=2;i<n;i++)
{
addedge(IN(i),OU(i),1,0);
}
addedge(IN(1),OU(1),INF,0);
addedge(IN(n),OU(n),INF,0);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
addedge(OU(a),IN(b),1,c);
}
s=IN(1);
t=OU(n);
}
int main()
{
init();
minflow();
printf("%d %d\n",tot,ans);
return 0;
}
bzoj 1221 软件开发
http://www.lydsy.com/JudgeOnline/problem.php?id=1221
好题费用流
建图挺巧: 把每天拆成两个点,分别记为Xi,Yi,从S向Xi连一条流量为INF,费用为f的边。从S向Yi连一条流量ni,费用为0的边。从Yi向Yi+1连一条流量INF,费用为0的边(这步很巧,如果直接向T连会TLE)。从Yi向Xi+a连一条流量为INF,费用为fa的边。从Yi向Xi+b连一条流量为INF,费用为fb的边。从Xi向T连一条流量为ni,费用为0的边。这个网络的最小费用最大流的费用就是答案。贴代码:
#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 1050
#define INF 0x3f3f
using namespace std;
struct Edge{
int v,w,f,nxt;
Edge() {};
Edge(int a,int b,int c,int d)
{
v=a,f=b,w=c,nxt=d;
}
}e[MAXN*15];
int g[MAXN*15];
int n,m,eid;
int s,t;
inline void addedge(int u,int v,int c,int w)
{
e[++eid]=Edge(v,c,w,g[u]);
g[u]=eid;
e[++eid]=Edge(u,0,-w,g[v]);
g[v]=eid;
}
int pree[MAXN*3];
int prevv[MAXN*3];
int dis[MAXN*3];
bool vis[MAXN*3];
inline bool findPath()
{
queue<int >q;
//memset(vis,false,sizeof(vis));
q.push(s);
// memset(pree,0,sizeof(pree));
// memset(prevv,0,sizeof(prevv));
memset(dis,INF,sizeof(dis));
dis[s]=0;vis[s]=true;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]>dis[u]+e[i].w)
{
dis[e[i].v]=dis[u]+e[i].w;
pree[e[i].v]=i;
prevv[e[i].v]=u;
if(!vis[e[i].v])
{
vis[e[i].v]=true;q.push(e[i].v);
}
}
vis[u]=false;
}
if(dis[t]<INF) return true;
return false;
}
inline int augment()
{
int u=t,delta=INF;
while(u!=s)
{
delta=min(delta,e[pree[u]].f);
u=prevv[u];
}
u=t;
while(u!=s)
{
e[pree[u]].f-=delta;
e[pree[u]^1].f+=delta;
u=prevv[u];
}
return delta*dis[t];
}
inline int minflow()
{
int cur=0;
while(findPath())
{
cur+=augment();
}
return cur;
}
inline int IN(int i)
{
return i;
}
inline int OU(int i)
{
return n+i;
}
void init()
{
eid=1;
int a,b,f,fa,fb;
scanf("%d%d%d%d%d%d",&n,&a,&b,&f,&fa,&fb);
s=2*n+1,t=2*n+2;
for (int i=1;i<=n;i++) addedge(s,i,INF,f);
for (int i=1;i<=n-1;i++) addedge(n+i,n+i+1,INF,0);
for (int i=1;i<=n-a-1;i++) addedge(n+i,i+a+1,INF,fa);
for (int i=1;i<=n-b-1;i++) addedge(n+i,i+b+1,INF,fb);
for (int i=1;i<=n;i++){
int x;
scanf("%d",&x);
addedge(i,t,x,0);
addedge(s,i+n,x,0);
}
}
int main()
{
init();
printf("%d\n",minflow());
return 0;
}
bzoj 2127 happiness
http://www.lydsy.com/JudgeOnline/problem.php?id=2127
太神了。。。。说不清楚。。。。还是直接贴代码吧:
别人的:
Time:1508 ms
Memory:4988 kb
#include<iostream>
#include<cstring>
#include<cstdio>
#define T 10001
#define inf 0x7fffffff
#define FOR for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
#define rep(x,y) for(int i=1;i<=x;i++)for(int j=1;j<=y;j++)
#define ll long long
using namespace std;
int n,m,ans,tot,cnt=1,head[10002],h[10002];
int a[101][101],b[101][101],mark[101][101];
int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0};
struct data{int to,next,v;}e[300001];
void ins(int u,int v,int w)
{cnt++;e[cnt].to=v;e[cnt].v=w;e[cnt].next=head[u];head[u]=cnt;}
void insert(int u,int v,int w)
{ins(u,v,w);ins(v,u,0);}
void ins2(int u,int v,int w)
{ins(u,v,w);ins(v,u,w);}
bool bfs()
{
int q[10005],t=0,w=1,i,now;
memset(h,-1,sizeof(h));
q[0]=h[0]=0;
while(t!=w)
{
now=q[t];t++;if(t==10001)t=0;
for(i=head[now];i;i=e[i].next)
{
if(e[i].v&&h[e[i].to]<0)
{h[e[i].to]=h[now]+1;q[w++]=e[i].to;if(w==10001)w=0;}
}
}
if(h[T]==-1)return 0;return 1;
}
int dfs(int x,int f)
{
if(x==T)return f;
int w,used=0;
for(int i=head[x];i;i=e[i].next)
{
if(e[i].v&&h[e[i].to]==h[x]+1)
{
w=f-used;
w=dfs(e[i].to,min(w,e[i].v));
e[i].v-=w;e[i^1].v+=w;
used+=w;if(used==f)return f;
}
}
if(!used)h[x]=-1;
return used;
}
void dinic(){while(bfs())ans+=dfs(0,inf);}
void build()
{
int x;
rep(n-1,m)
{
scanf("%d",&x);tot+=x;
a[i][j]+=x;a[i+1][j]+=x;
ins2(mark[i][j],mark[i+1][j],x);
}
rep(n-1,m)
{
scanf("%d",&x);tot+=x;
b[i][j]+=x;b[i+1][j]+=x;
ins2(mark[i][j],mark[i+1][j],x);
}
rep(n,m-1)
{
scanf("%d",&x);tot+=x;
a[i][j]+=x;a[i][j+1]+=x;
ins2(mark[i][j],mark[i][j+1],x);
}
rep(n,m-1)
{
scanf("%d",&x);tot+=x;
b[i][j]+=x;b[i][j+1]+=x;
ins2(mark[i][j],mark[i][j+1],x);
}//cout<<tot<<endl;
FOR{
insert(0,mark[i][j],a[i][j]);
insert(mark[i][j],T,b[i][j]);
}
}
int main()
{
scanf("%d%d",&n,&m);
FOR scanf("%d",&a[i][j]),tot+=a[i][j],a[i][j]<<=1;
FOR scanf("%d",&b[i][j]),tot+=b[i][j],b[i][j]<<=1;
FOR mark[i][j]=(i-1)*m+j;
build();dinic();
//cout<<tot<<endl;
printf("%d",tot-(ans>>1));
return 0;
}
自己的(慢爆了,还是不知道为什么。。QAQ):
Time:32484 ms
Memory:5308 kb
#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#define FOR for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
#define rep(x,y) for(int i=1;i<=x;i++) for(int j=1;j<=y;j++)
#define INF 0x3f3f
using namespace std;
struct Edge{
int v,f,nxt;
Edge(){};
Edge(int a,int b,int c) { v=a, f=b, nxt=c;}
}e[300005];
int g[50005];
int a[101][101],b[101][101],mark[101][101];
int s,t,n,m,eid,tot;
inline void ins(int u,int v,int f)
{
++eid;
e[eid]=Edge(v,f,g[u]);
g[u]=eid;
}
inline void addedge(int u,int v,int f)
{ins(u,v,f);ins(v,u,0);}
inline void add2(int u,int v,int f)
{ins(u,v,f);ins(v,u,f);}
int dis[50005];
queue<int >q;
bool bfs()
{
while(!q.empty())q.pop();
memset(dis,0,sizeof(dis));
int i,u,v;
q.push(s),dis[s]=1;
while(!q.empty())
{
u=q.front(),q.pop();
for(i=g[u];i;i=e[i].nxt)
{
v=e[i].v;
if(!dis[v]&&e[i].f)
{
dis[v]=dis[u]+1;
if(v==t)return 1;
q.push(v);
}
}
}
return 0;
}
inline int dfs(int u,int delta)
{
if(u==t)
return delta;
else
{
int ret=0;
for(int i=g[u];delta&&i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]==dis[u]+1)
{
int dd=dfs(e[i].v,min(e[i].f,delta));
if(!dd) dis[e[i].v]=0;
delta-=dd;
e[i].f-=dd;
e[i^1].f+=dd;
ret+=dd;
}
return ret;
}
}
int maxflow()
{
int ret=0;
while(bfs())
{
ret+=dfs(s,INF);
}
return ret;
}
inline void init()
{
eid=1;
scanf("%d%d",&n,&m);
FOR scanf("%d",&a[i][j]),tot+=a[i][j],a[i][j]<<=1;
FOR scanf("%d",&b[i][j]),tot+=b[i][j],b[i][j]<<=1;
FOR mark[i][j]=(i-1)*m+j;
int x;
rep(n-1,m)
{
scanf("%d",&x);tot+=x;
a[i][j]+=x;a[i+1][j]+=x;
add2(mark[i][j],mark[i+1][j],x);
}
rep(n-1,m)
{
scanf("%d",&x);tot+=x;
b[i][j]+=x;b[i+1][j]+=x;
add2(mark[i][j],mark[i+1][j],x);
}
rep(n,m-1)
{
scanf("%d",&x);tot+=x;
a[i][j]+=x;a[i][j+1]+=x;
add2(mark[i][j],mark[i][j+1],x);
}
rep(n,m-1)
{
scanf("%d",&x);tot+=x;
b[i][j]+=x;b[i][j+1]+=x;
add2(mark[i][j],mark[i][j+1],x);
}//cout<<tot<<endl;
s=10002,t=10001;
FOR{
addedge(s,mark[i][j],a[i][j]);
addedge(mark[i][j],t,b[i][j]);
}
}
int main()
{
init();
int ans=maxflow();
//printf("%d\n",ans);
printf("%d\n",tot-(ans>>1));
return 0;
}
bzoj 3931 网络吞吐量
http://www.lydsy.com/JudgeOnline/problem.php?id=3931
费用流
第一问裸最大流,第二问直接在原图上建就行了
贴代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
using namespace std;
#define dout printf
typedef long long ll;
const int Maxn=1010;
const ll INF=4557430888798830399ll;
int n,m,N;
ll g[Maxn][Maxn];
ll d[Maxn*2];
bool flag[Maxn];
struct Edge{
int to;
ll cap,flow;
int next;
Edge(int to=0,ll cap=0,int next=0):to(to),cap(cap),next(next){
flow=0;
}
ll adv(){
return cap-flow;
}
}edges[2000010];int tot=1,fir[Maxn*2];
void AddEdge(int from,int to,ll cap){
edges[++tot]=Edge(to,cap,fir[from]);fir[from]=tot;
edges[++tot]=Edge(from,0,fir[to]);fir[to]=tot;
}
void init(){
scanf("%d%d",&n,&m);N=2*n;
memset(g,0x3f,sizeof g);
for(int u,v,w,i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
if(g[u][v]>w) g[u][v]=g[v][u]=w;
}
for(int c,i=1;i<=n;i++){
scanf("%d",&c);
AddEdge(i,i+n,(i==1||i==n)?INF:c);
}
}
void Dijkstra(){
memset(d,0x3f,sizeof d);
memset(flag,0,sizeof flag);
d[1]=0;
ll MN;
int u;
for(int T=n;T--;){
MN=INF;
for(int i=1;i<=n;i++) if(!flag[i] && d[i]<MN) {
MN=d[i]; u=i;
}
flag[u]=1;
for(int i=1;i<=n;i++){
d[i]=min(d[i],d[u]+g[u][i]);
}
}
}
int q[Maxn],ql,qr;
void build(){
q[qr=(ql=0)+1]=n;
memset(flag,0,sizeof flag);
for(;ql<qr;){
int u=q[++ql];
for(int v=1;v<=n;v++)if(u!=v && d[v]+g[u][v]==d[u]){
AddEdge(v+n,u,INF);
if(!flag[v]) q[++qr]=v,flag[v]=1;
}
}
}
// network-flows begin----------------------------------------------
int s,t;
int p[Maxn*2],cur[Maxn*2],num[Maxn*2];
#define e edges[i]
inline ll Augment(){
ll a=INF;
for(int x=t;x!=s;x=edges[p[x]^1].to){
a=min(a,edges[p[x]].adv());
}
for(int x=t;x!=s;x=edges[p[x]^1].to){
edges[p[x]].flow+=a;
edges[p[x]^1].flow-=a;
}
return a;
}
inline void BFS(int start,bool flag){
for(int i=1;i<=N;i++)d[i]=N;
d[q[qr=(ql=0)+1]=start]=0;
for(int x;ql<qr;){
x=q[++ql];
for(int i=fir[x];i;i=e.next){
if((flag^(bool)e.adv())&&d[e.to]==N){
d[q[++qr]=e.to]=d[x]+1;
}
}
}
}
inline ll ISAP(){
s=1,t=N;
BFS(t,1);
ll flow=0;
memcpy(cur,fir,sizeof cur);
for(int i=1;i<=N;i++)num[d[i]]++;
for(int i=1;i<=d[s];i++)if(!num[i])return 0;
for(int x=s;d[s]<N;){
if(x==t){
flow+=Augment();
x=s;
}
int ok=0;
for(int&i=cur[x];i;i=e.next){
if(e.adv()&&d[x]==d[e.to]+1){
p[x=e.to]=i;
ok=1;
break;
}
}
if(!ok){
int M=N;
for(int i=fir[x];i;i=e.next){
if(e.adv())M=min(M,(int)d[e.to]+1);
}
if(!--num[d[x]])break;
num[d[x]=M]++;
cur[x]=fir[x];
if(x!=s)x=edges[p[x]^1].to;
}
}
return flow;
}
//network-flows end-----------------------------------------------------------
int main(){
//freopen("network.in","r",stdin);
//freopen("network.out","w",stdout);
init();
Dijkstra();
build();
cout<<ISAP();
return 0;
}
~~~~~以后还会补充的~~~
省选 rp++ bless me ~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~··2015.4.22更新~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~··
最近发现了我的网络流模板里的一个超大超大超大的BUG(现在才发现........)
dfs()中如果ret为0要更改dis[u]。。。不加会T (为什么有些题没加就过了呢
就不贴模板了,上面几道题里面有模板
(省选完跪,马丹,D1T1 网络流+二分 开始写了正解,想多了,就改了!!!!人弱没办法。。。。。
(不过,明年的我会强大的。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~··2015.4.30更新~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~··
bzoj 2661 连连看
http://www.lydsy.com/JudgeOnline/problem.php?id=2661
建图的时候流量用1000减i+j,再SPFA,不然就要求最长路了(不建议)
贴代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<iostream>
#define MAXN 2000005
#define M 20000
#define INF 10000
using namespace std;
inline int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int s,t,eid;
bool jud(int x,int y)
{
if(gcd(x,y)!=1)return 0;
int t1=y*y-x*x,t2=sqrt(t1);
if(t2*t2!=t1)return 0;
return 1;
}
int g[M];
struct Edge
{
Edge() {};
Edge(int a,int b,int c,int d)
{
v=a;
f=b;
w=c;
nxt=d;
}
int v,f,w,nxt;
}e[MAXN];
inline void addedge(int u,int v,int f,int w)
{
e[++eid]=Edge(v,f,w,g[u]);
g[u]=eid;
e[++eid]=Edge(u,0,-w,g[v]);
g[v]=eid;
}
int vis[M],dis[M];
int prev[M],pree[M];
bool findPath()
{
queue<int >q;
q.push(s);
for(int i=1;i<M;i++)
dis[i]=INF*10000;
dis[s]=0;
vis[s]=true;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u]; i; i=e[i].nxt)
if(e[i].f>0&&dis[u]+e[i].w<dis[e[i].v])
{
dis[e[i].v]=dis[u]+e[i].w;
prev[e[i].v]=u;
pree[e[i].v]=i;
if(!vis[e[i].v])
{
vis[e[i].v]=true;
q.push(e[i].v);
}
}
vis[u]=false;
}
//cout<<dis[t]<<endl;
if(dis[t]!=INF*10000) return true;
else return false;
}
int augment()
{
int u=t;
int delta=0x3f3f3f;
while(u!=s)
{
delta=min(delta,e[pree[u]].f);
u=prev[u];
}
u=t;
while(u!=s)
{
e[pree[u]].f-=delta;
e[pree[u]^1].f+=delta;
u=prev[u];
}
return dis[t]*delta;
}
int tot,ans;
int c[1000001];
int L[1010],R[1010],b[1010];
int cnt;
inline void init()
{
int n,m,i,j,k;
eid=1;
cin>>n>>m;
for(i=1;i<=1000;i++) c[i*i]=i;
for(i=n;i<=m;i++) for(j=i+1;j<=m;j++)
{
k=j*j-i*i;
if(c[k]&&gcd(i,c[k])==1)
{
b[i]=b[j]=1;
cnt++;
L[cnt]=i; R[cnt]=j;
}
}
int x=0;
for(i=n;i<=m;i++) if(b[i]) b[i]=++x;
s=2800; t=2801;
for(i=n;i<=m;i++) if(b[i])addedge(s,b[i],1,0),addedge(b[i]+x,t,1,0);
for(int i=1;i<=cnt;i++)
{
addedge(b[L[i]],x+b[R[i]],1,INF-L[i]-R[i]);
addedge(b[R[i]],x+b[L[i]],1,INF-L[i]-R[i]);
}
}
int minflow()
{
while(findPath())
{
tot++;
ans+=augment();
}
printf("%d %d\n",tot>>1,(tot*INF-ans)>>1);
}
int main()
{
init();
minflow();
return 0;
}
bzoj 1305 dance跳舞
http://www.lydsy.com/JudgeOnline/problem.php?id=1305
还是比较好想的
贴代码:
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#define MAXN 500001
#define M 1005
using namespace std;
int n,s,t,eid,k;
struct Edge{
int v,f,nxt;
}e[MAXN];
int g[M];
int mapp[M][M];
char ch[M][M];
inline void addedge(int u,int v,int f)
{
e[++eid].f=f,e[eid].v=v,e[eid].nxt=g[u];
g[u]=eid;
e[++eid].f=0,e[eid].v=u,e[eid].nxt=g[v];
g[v]=eid;
}
bool vis[M];
int dis[M];
inline bool bfs()
{
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
queue<int >q;
q.push(s);
vis[s]=true;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&!vis[e[i].v])
{
vis[e[i].v]=true;
q.push(e[i].v);dis[e[i].v]=dis[u]+1;
}
}
return vis[t];
}
inline int dfs(int u,int delta)
{
if(u==t)
return delta;
else
{
int ret=0;
for(int i=g[u];delta&&i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]==dis[u]+1)
{
int dd=dfs(e[i].v,min(e[i].f,delta));
e[i].f-=dd;
e[i^1].f+=dd;
ret+=dd;
delta-=dd;
}
if(!ret)
dis[u]=-2;
return ret;
}
}
inline int maxflow()
{
int ret=0;
while(bfs())
{
ret+=dfs(s,0x3f3f3f);
}
return ret;
}
void init()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
scanf("%s",ch[i]+1);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
if(ch[i][j]=='Y')
mapp[i][j]=1;else mapp[i][j]=0;
}
bool jud(int maxf)
{
eid=1;
s=1001,t=1002;
memset(g,0,sizeof(g));
for(int i=1;i<=n;i++)addedge(s,i,maxf);
for(int i=1;i<=n;i++)addedge(i,i+500,k);
for(int i=1;i<=n;i++)addedge(n+i+500,n+i,k);
for(int i=1;i<=n;i++)addedge(n+i,t,maxf);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(mapp[i][j])addedge(i,n+j,1);
else addedge(i+500,n+j+500,1);
int ans=maxflow();
if(maxf*n>ans)
return false;
else
return true;
}
int main()
{
init();
int l=0,r=50; int mid,mx=0;
while(l<=r)
{
mid=(l+r)>>1;
if(jud(mid)){mx=mid;l=mid+1;}
else r=mid-1;
}
cout<<mx<<endl;
return 0;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~2015.5.10更新~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bzoj 1570
http://www.lydsy.com/JudgeOnline/problem.php?id=1570
对于每天都添边,一共只用n+k(最多)再判断最大流==k 满足即输出
详细点的:
每一天对于航班f[i],建f[i].from->f[i].to 容量为f[i].c
N个城市昨天和今天连边 容量为inf
S->1 容量 k
每一天n->T 容量inf
贴代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define MAXN 1001001
#define M 5050
using namespace std;
struct Edge
{
int v,f,nxt;
} e[MAXN];
struct flight
{
int x,y,z;
void Read()
{
cin>>x>>y>>z;
}
} f[M];
int s,t,eid,n,m,k;
int g[M];
int dis[M];
bool vis[M];
inline void addedge(int u,int v,int f)
{
e[++eid].f=f,e[eid].v=v,e[eid].nxt=g[u];
g[u]=eid;
e[++eid].f=0,e[eid].v=u,e[eid].nxt=g[v];
g[v]=eid;
}
inline bool bfs()
{
queue<int >q;
memset(vis,false,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
q.push(s);
vis[s]=true;
dis[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u]; i; i=e[i].nxt)
if(e[i].f&&!vis[e[i].v])
{
dis[e[i].v]=dis[u]+1;
vis[e[i].v]=true;
q.push(e[i].v);
}
}
return vis[t];
}
inline int dfs(int u,int delta)
{
if(u==t)
return delta;
int ret=0;
for(int i=g[u]; delta&&i; i=e[i].nxt)
if(e[i].v&&dis[e[i].v]==dis[u]+1)
{
int dd=dfs(e[i].v,min(delta,e[i].f));
ret+=dd;
delta-=dd;
e[i].f-=dd;
e[i^1].f+=dd;
}
if(!ret)
dis[u]=-3;
return ret;
}
int main()
{
cin>>n>>m>>k;
for(int i=1; i<=m; i++)
{
f[i].Read();
}
int ans=0;
eid=1;
s=5040;
t=5041;
addedge(s,1,k);
for(int i=1; i<=n+k; i++)
{
for(int j=1; j<=m; j++)
addedge(i*n-n+f[j].x,i*n+f[j].y,f[j].z);
for(int j=1; j<=n; j++)
addedge(i*n-n+j,i*n+j,0x3f3f3f);
addedge(i*n+n,t,0x3f3f3f);
while(bfs())
ans+=dfs(s,0x3f3f3f);
if(ans==k)
{
cout<<i<<endl;
return 0;
}
}
return 0;
}
bzoj 1934
http://www.lydsy.com/JudgeOnline/problem.php?id=1934
明显最小割
对于每个小孩X
同意 S->X 容量为1
否则 X>T 容量为1
然后对于好朋友u,v
连 u->v 容量1 v->u 容量1
跑最小割
贴代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define MAXN 350
using namespace std;
struct Edge{
int v,f,nxt;
}e[MAXN*MAXN+MAXN*3+100];
int g[MAXN];
int eid,s,t,n,m;
inline void addedge(int u,int v,int f)
{
e[++eid].f=f,e[eid].v=v,e[eid].nxt=g[u];
g[u]=eid;
e[++eid].f=0,e[eid].v=u,e[eid].nxt=g[v];
g[v]=eid;
}
bool vis[MAXN];
int dis[MAXN];
inline bool bfs()
{
queue<int >q;
q.push(s);
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
vis[s]=true;
dis[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&!vis[e[i].v])
{
dis[e[i].v]=dis[u]+1;
q.push(e[i].v);
vis[e[i].v]=true;
}
}
return vis[t];
}
inline int dfs(int u,int delta)
{
if(u==t)
return delta;
int ret=0;
for(int i=g[u];delta&&i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]==dis[u]+1)
{
int dd=dfs(e[i].v,min(e[i].f,delta));
ret+=dd;
delta-=dd;
e[i].f-=dd;
e[i^1].f+=dd;
}
if(!ret)
dis[u]=-3;
return ret;
}
inline int maxflow()
{
int ret=0;
while(bfs())
ret+=dfs(s,0x3f3f3f);
return ret;
}
int main()
{
cin>>n>>m;
eid=1,s=340,t=s+1;
for(int i=1,x;i<=n;i++)
{
scanf("%d",&x);
if(x)
addedge(s,i,1);
else
addedge(i,t,1);
}
for(int i=1,u,v;i<=m;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v,1);
addedge(v,u,1);
}
int ans=maxflow();
cout<<ans<<endl;
return 0;
}
bzoj 1433
http://www.lydsy.com/JudgeOnline/problem.php?id=1433
建图挺巧的
住校的人的床连T 容量1
每对认识的连人和床
比如 1 来看的人 2 住读 1认识2 就 1连2 的床容量1
S连每个学生 容量1
自己也要和自己的床连
贴代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#define M 300
using namespace std;
int s,t,eid,k,n;
struct Edge
{
int v,f,nxt;
} e[5010];
int g[M];
inline void addedge(int u,int v,int f)
{
e[++eid].f=f,e[eid].v=v,e[eid].nxt=g[u];
g[u]=eid;
e[++eid].f=0,e[eid].v=u,e[eid].nxt=g[v];
g[v]=eid;
}
int dis[M];
bool vis[M];
inline bool bfs()
{
queue<int > q;
q.push(s);
memset(vis,false,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
vis[s]=true;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u]; i; i=e[i].nxt)
if(e[i].f&&!vis[e[i].v])
{
dis[e[i].v]=dis[u]+1;
vis[e[i].v]=true;
q.push(e[i].v);
}
}
return vis[t];
}
inline int dfs(int u,int delta)
{
if(u==t)
return delta;
int ret=0;
for(int i=g[u]; delta&&i; i=e[i].nxt)
if(e[i].f&&dis[e[i].v]==dis[u]+1)
{
int dd=dfs(e[i].v,min(e[i].f,delta));
ret+=dd;
delta-=dd;
e[i].f-=dd;
e[i^1].f+=dd;
}
if(!ret)
dis[u]=-4;
return ret;
}
inline int maxflow()
{
int ret=0;
while(bfs())
ret+=dfs(s,0x3f3f);
return ret;
}
inline void init()
{
eid=1;
int tot=0;
memset(g,0,sizeof(g));
scanf("%d",&n);
int num[100];
s=2*n+1,t=s+1;
for(int i=1; i<=n; i++)
{
scanf("%d",&num[i]);
if(num[i])
addedge(i+n,t,1);
}
for(int i=1; i<=n; i++)
{
int x;
scanf("%d",&x);
if(!num[i]||num[i]&&!x)
addedge(s,i,1),tot++;
}
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
int x;
scanf("%d",&x);
if(x||i==j)
addedge(i,j+n,1);
}
int ans=maxflow();
if(ans>=tot)
puts("^_^");
else puts("T_T");
}
int main()
{
scanf("%d",&k);
for(int i=1;i<=k;i++)
init();
return 0;
}
bzoj 1412
http://www.lydsy.com/JudgeOnline/problem.php?id=1412
最小割
狼和周围的羊连边 容量1
S连狼 ,羊连T
空地也要连!!!!
贴代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define MAXN 5000100
#define M 15000
#define INF 0x3f3f3f
using namespace std;
struct Edge
{
int v,f,nxt;
} e[MAXN];
int eid,s,t,n,m;
int mapp[110][110];
int g[M];
inline void addedge(int u,int v,int f)
{
e[++eid].f=f,e[eid].v=v,e[eid].nxt=g[u];
g[u]=eid;
e[++eid].f=0,e[eid].v=u,e[eid].nxt=g[v];
g[v]=eid;
}
bool vis[M];
int dis[M];
int dx[4]={-1,0,0,1},dy[4]={0,-1,1,0};
inline bool bfs()
{
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
queue<int >q;
q.push(s);
vis[s]=true;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&!vis[e[i].v])
{
vis[e[i].v]=true;
q.push(e[i].v);dis[e[i].v]=dis[u]+1;
}
}
return vis[t];
}
inline int dfs(int u,int delta)
{
if(u==t)
return delta;
else
{
int ret=0;
for(int i=g[u];delta&&i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]==dis[u]+1)
{
int dd=dfs(e[i].v,min(e[i].f,delta));
e[i].f-=dd;
e[i^1].f+=dd;
ret+=dd;
delta-=dd;
}
if(!ret)
dis[u]=-2;
return ret;
}
}
inline int maxflow()
{
int ret=0;
while(bfs())
{
ret+=dfs(s,0x3f3f3f);
}
return ret;
}
int num(int i,int j)
{
return (i-1)*m+j;
}
void init()
{
cin>>n>>m;
eid=1;
memset(g,0,sizeof(g));
s=14400,t=s+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&mapp[i][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(mapp[i][j]==1)addedge(s,(i-1)*m+j,INF);
else if(mapp[i][j]==2)addedge((i-1)*m+j,t,INF);
for(int k=0;k<4;k++)
{
int nowx=i+dx[k],nowy=j+dy[k];
if(nowx<1||nowx>n||nowy<1||nowy>m||mapp[i][j]==2)continue;
if(mapp[i][j]!=1||mapp[nowx][nowy]!=1)
addedge((i-1)*m+j,(nowx-1)*m+nowy,1);
}
}
int ans=maxflow();
cout<<ans<<endl;
}
int main()
{
init();
return 0;
}
bzoj 2424
http://www.lydsy.com/JudgeOnline/problem.php?id=2424
费用流
呵呵哒,这道题我一开始想多了
X连T 容量Ui,费用0
S 连X 容量inf 费用di
每个月I 向i+1 连 容量为si,费用为mi (一开始我容量设成Ui-si了
贴代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#define MAXN 1000010
#define M 200
using namespace std;
struct Edge{
int v,f,nxt,w;
Edge(){};
Edge(int a,int b,int c,int d )
{
v=b;f=c;nxt=a;w=d;
}
}e[MAXN];
int eid,g[M],n,m,S,s,t;
inline void addedge(int u,int v,int f,int w)
{
e[++eid]=Edge(g[u],v,f,w);
g[u]=eid;
e[++eid]=Edge(g[v],u,0,-w);
g[v]=eid;
}
bool vis[M];
int dis[M],prev[M],pree[M];
bool findPath()
{
queue<int >q;
q.push(s);
memset(dis,0x3f3f3f,sizeof(dis));
dis[s]=0;
vis[s]=true;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u]; i; i=e[i].nxt)
if(e[i].f>0&&dis[u]+e[i].w<dis[e[i].v])
{
dis[e[i].v]=dis[u]+e[i].w;
prev[e[i].v]=u;
pree[e[i].v]=i;
if(!vis[e[i].v])
{
vis[e[i].v]=true;
q.push(e[i].v);
}
}
vis[u]=false;
}
if(dis[t]<0x3f3f3f) return true;
else return false;
}
int augment()
{
int u=t;
int delta=0x3f3f3f;
while(u!=s)
{
delta=min(delta,e[pree[u]].f);
u=prev[u];
}
u=t;
while(u!=s)
{
e[pree[u]].f-=delta;
e[pree[u]^1].f+=delta;
u=prev[u];
}
return dis[t]*delta;
}
int minflow()
{
int cur=0;
while(findPath())
{
cur+=augment();
// cout<<cur<<endl;
}
return cur;
}
void init()
{
cin>>n>>m>>S;
eid=1;
s=150,t=s+1;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
addedge(i,t,x,0);
}
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
addedge(s,i,0x3f3f3f,x);
}
for(int i=1;i<n;i++)
addedge(i,i+1,S,m);
int ans=minflow();
cout<<ans<<endl;
}
int main()
{
init();
return 0;
}
bzoj 3993
http://www.lydsy.com/JudgeOnline/problem.php?id=3993
二分+最大流验证
二分最小时间k
S ->激光武器i 容量k*B[i];
机器人->T 容量A[i];
对于每对可攻击的激光武器和机器人连边 容量inf
这道题不同的地方时要注意精度问题
贴代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#define MAXN 500010
#define M 200
#define eps 1e-9
#define INF 1e9
using namespace std;
typedef double df;
struct Edge{
int v,nxt;
df f;
}e[MAXN];
int g[M],dis[M],eid,s,t,n,m,sum;
bool vis[M];
int A[M],B[M];
bool mapp[60][60];
inline void addedge(int u,int v,df f)
{
e[++eid].f=f,e[eid].v=v,e[eid].nxt=g[u];
g[u]=eid;
e[++eid].f=0,e[eid].v=u,e[eid].nxt=g[v];
g[v]=eid;
}
inline bool bfs()
{
queue<int >q;
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
q.push(s);
vis[s]=true;
dis[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&!vis[e[i].v])
{
dis[e[i].v]=dis[u]+1;
vis[e[i].v]=true;
q.push(e[i].v);
}
}
return vis[t];
}
inline df dfs(int u,df delta)
{
if(u==t)
return delta;
df ret=0;
for(int i=g[u];delta&&i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]==dis[u]+1)
{
df dd=dfs(e[i].v,min(e[i].f,delta));
ret+=dd;
delta-=dd;
e[i].f-=dd;
e[i^1].f+=dd;
}
if(!ret)
dis[u]=-3;
return ret;
}
inline df maxflow()
{
df ret=0.0;
while(bfs())
ret+=dfs(s,INF);
return ret;
}
df l,r,mid;
inline bool jud(df k)
{
eid=1;
memset(g,0,sizeof(g));
for(int i=1;i<=m;i++)
addedge(s,i,k*B[i]);
for(int i=1;i<=n;i++)
addedge(i+m,t,A[i]);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if(mapp[i][j])
addedge(i,j+m,INF);
df ans=maxflow();
return fabs(ans-sum)<eps;
}
int main()
{
l=0;
cin>>n>>m;
s=150,t=s+1;
for(int i=1;i<=n;i++)
{
cin>>A[i];
r+=A[i];
sum+=A[i];
}
for(int i=1;i<=m;i++)
{
cin>>B[i];
}
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
cin>>mapp[i][j];
}
while(l+1e-4<r)
{
mid=(l+r)/2;
if(jud(mid))
r=mid;
else
l=mid;
}
printf("%.4lf\n",(double)l);
return 0;
}
bzoj 3144
http://www.lydsy.com/JudgeOnline/problem.php?id=3144
最大流
能连的都连,向四周;
S向第一层连,最后一层向T连
贴代码:
#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
#define MAXN 50*50*50*10
#define M 40*40*40*10
#define INF 0x3f3f3f
using namespace std;
struct Edge{
int v,f,nxt;
}e[MAXN];
const int dx[] = {0,1,-1,0,0};
const int dy[] = {0,0,0,1,-1};
int eid,s,t,g[M];
int n,m,k,d;
int val;
inline void addedge(int u,int v,int f)
{
e[++eid].f=f,e[eid].v=v,e[eid].nxt=g[u];
g[u]=eid;
e[++eid].f=0,e[eid].v=u,e[eid].nxt=g[v];
g[v]=eid;
}
int dis[M];
bool vis[M];
inline bool bfs()
{
queue<int >q;
q.push(s);
memset(vis,false,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
vis[s]=true;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&!vis[e[i].v])
{
dis[e[i].v]=dis[u]+1;
q.push(e[i].v);
vis[e[i].v]=true;
}
}
return vis[t];
}
inline int dfs(int u,int delta)
{
if(u==t)
return delta;
int ret=0;
for(int i=g[u];delta&&i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]==dis[u]+1)
{
int dd=dfs(e[i].v,min(e[i].f,delta));
ret+=dd;
delta-=dd;
e[i].f-=dd;
e[i^1].f+=dd;
}
if(!ret)
dis[u]=-3;
return ret;
}
inline int maxflow()
{
int ret=0;
while(bfs())
ret+=dfs(s,0x3f3f);
return ret;
}
inline int l(int i,int j,int q)
{
return (q-1)*n*m+(i-1)*m+j;
}
inline int r(int i,int j,int q)
{
return l(i,j,q)+n*m*k;
}
void init()
{
eid=1;
cin>>n>>m>>k>>d;
s=n*m*k*2+10;
t=s+1;
for(int i=1;i<=k;i++)
{
for(int j=1;j<=n;j++)
for(int p=1;p<=m;p++)
{
scanf("%d",&val);
addedge(l(j,p,i),r(j,p,i),val);
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
addedge(s,l(i,j,1),INF),addedge(r(i,j,k),t,INF);
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++)
for(int p=1;p<=m;p++)
{
if(i!=k)
addedge(r(j,p,i),l(j,p,i+1),INF);
for(int b=1;b<=4;b++)
{
int nx=j+dx[b],ny=p+dy[b];
if(nx<1||nx>n||ny<1||ny>m)
continue;
if(i-d>0)
addedge(l(j,p,i),l(nx,ny,i-d),INF);
}
}
int ans=maxflow();
cout<<ans<<endl;
}
int main()
{
init();
return 0;
}
bzoj 3504
http://www.lydsy.com/JudgeOnline/problem.php?id=3504
明显的最大流验证
但还要反过来从b2->b1验证
贴代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define inf 0x7fffffff
#define ll long long
#define T 51
using namespace std;
bool flag;
int n,a1,a2,an,b1,b2,bn;
int cnt,ans;
int h[55],q[55];
int mp[55][55];
struct data{int to,next,v;}e[100005];int head[55],cur[55];
void ins(int u,int v,int w)
{e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].v=w;}
void insert(int u,int v,int w)
{ins(u,v,w);ins(v,u,0);}
void build()
{
memset(head,0,sizeof(head));cnt=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(mp[i][j]==1)insert(i,j,2);
else if(mp[i][j]==2)insert(i,j,inf);
}
bool bfs()
{
int t=0,w=1;
for(int i=0;i<=T;i++)h[i]=-1;
q[0]=0;h[0]=0;
while(t!=w)
{
int now=q[t];t++;
for(int i=head[now];i;i=e[i].next)
if(e[i].v&&h[e[i].to]==-1)
{
h[e[i].to]=h[now]+1;
q[w++]=e[i].to;
}
}
if(h[T]==-1)return 0;
return 1;
}
int dfs(int x,int f)
{
if(x==T)return f;
int w,used=0;
for(int i=cur[x];i;i=e[i].next)
{
if(e[i].v&&h[e[i].to]==h[x]+1)
{
w=f-used;
w=dfs(e[i].to,min(e[i].v,w));
e[i].v-=w;
if(e[i].v)cur[x]=i;
e[i^1].v+=w;
used+=w;if(used==f)return f;
}
}
if(!used)h[x]=-1;
return used;
}
void dinic()
{while(bfs()){for(int i=0;i<=T;i++)cur[i]=head[i];ans+=dfs(0,inf);}}
int main()
{
while(scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)!=EOF)
{
memset(mp,0,sizeof(mp));flag=0;
a1++;a2++;b1++;b2++;
for(int i=1;i<=n;i++)
{
char ch[55];
scanf("%s",ch);
for(int j=1;j<=n;j++)
if(ch[j-1]=='O')mp[i][j]=1;
else if(ch[j-1]=='N')mp[i][j]=2;
}
build();
insert(0,a1,an*2);insert(a2,T,an*2);
insert(0,b1,bn*2);insert(b2,T,bn*2);
ans=0;
dinic();
if(ans<2*(an+bn))flag=1;
if(!flag)
{
build();
insert(0,a1,an*2);insert(a2,T,an*2);
insert(0,b2,bn*2);insert(b1,T,bn*2);
ans=0;
dinic();
if(ans<2*(an+bn))flag=1;
}
if(flag)printf("No\n");
else printf("Yes\n");
}
return 0;
}
bzoj 2132
http://www.lydsy.com/JudgeOnline/problem.php?id=2132
记得这道题的思想很经典
就是两个选了会有代价,不选也会有代价
贴代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#define MAXN 1000000
#define M 120*120
using namespace std;
struct Edge{
int v,f,nxt;
}e[MAXN];
int dx[]={-1,0,0,1},dy[]={0,-1,1,0};
int s,t,n,m,eid;
int g[M];
int dis[M];
bool vis[M];
int A[120][120],B[120][120],C[120][120],c[120][120],num[120][120];
inline void addedge(int u,int v,int f)
{
e[++eid].f=f,e[eid].v=v,e[eid].nxt=g[u];
g[u]=eid;
e[++eid].f=0,e[eid].v=u,e[eid].nxt=g[v];
g[v]=eid;
}
inline bool bfs()
{
queue<int >q;
memset(vis,false,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
vis[s]=true;
dis[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&!vis[e[i].v])
{
dis[e[i].v]=dis[u]+1;
vis[e[i].v]=true;
q.push(e[i].v);
}
}
return vis[t];
}
inline int dfs(int u,int delta)
{
if(u==t)
return delta;
int ret=0;
for(int i=g[u];delta&&i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]==dis[u]+1)
{
int dd=dfs(e[i].v,min(e[i].f,delta));
e[i].f-=dd;
e[i^1].f+=dd;
delta-=dd;
ret+=dd;
}
return ret;
}
inline int maxflow()
{
int ret=0;
while(bfs())
ret+=dfs(s,0x3f3f3f);
return ret;
}
inline void Paint()
{
for(int i=1;i<=m;i++)
c[0][i]=1^c[0][i-1];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
c[i][j]=1^c[i-1][j],num[i][j]=(i-1)*m+j;
s=n*m+1;t=s+1;
}
inline void init()
{
cin>>n>>m;
eid=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>A[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>B[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>C[i][j];
Paint();
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(c[i][j])
addedge(s,num[i][j],A[i][j]),addedge(num[i][j],t,B[i][j]);
else
addedge(s,num[i][j],B[i][j]),addedge(num[i][j],t,A[i][j]);
ans+=A[i][j]+B[i][j];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
{
int nx=i+dx[k],ny=j+dy[k];
if(nx<1||ny<1||nx>n||ny>m)
continue;
int x=C[i][j]+C[nx][ny];
addedge(num[i][j],num[nx][ny],x);
ans+=C[i][j];
}
int tot=maxflow();
cout<<ans-tot<<endl;
}
int main()
{
init();
return 0;
}
bzoj 1927
http://www.lydsy.com/JudgeOnline/problem.php?id=1927
好像想想就能出来的。。。
贴代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#define MAXN 1000000
#define M 2000
using namespace std;
typedef long long ll;
struct Edge{
Edge() {};
Edge(int a,int b,int c,int d)
{
v=a,f=b,w=c,nxt=d;
}
int v,f,w,nxt;
}e[MAXN];
int eid,s,t,n,m;
int g[M];
int dis[M];
bool vis[M];
inline void addedge(int u,int v,int f,int w)
{
e[++eid]=Edge(v,f,w,g[u]);
g[u]=eid;
e[++eid]=Edge(u,0,-w,g[v]);
g[v]=eid;
}
int pree[M],prev[M];
inline bool findPath()
{
queue<int >q;
memset(dis,0x3f3f3fff,sizeof(dis));
dis[s]=0;
vis[s]=true;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]>dis[u]+e[i].w)
{
dis[e[i].v]=dis[u]+e[i].w;
pree[e[i].v]=i;
prev[e[i].v]=u;
if(!vis[e[i].v])
{
vis[e[i].v]=true;
q.push(e[i].v);
}
}
vis[u]=false;
}
return dis[t]<0x3f3f3fff;
}
ll augment()
{
int u=t,delta=0x3f3f3fff;
while(u!=s)
{
delta=min(e[pree[u]].f,delta);
u=prev[u];
}
u=t;
while(u!=s)
{
e[pree[u]].f-=delta;
e[pree[u]^1].f+=delta;
u=prev[u];
}
return delta*dis[t];
}
inline ll minflow()
{
ll ret=0;
while(findPath())
{
ret+=augment();
}
return ret;
}
inline void init()
{
cin>>n>>m;
eid=1;
s=n*2+1,t=s+1;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
addedge(s,i+n,1,x);
addedge(s,i,1,0);
addedge(i+n,t,1,0);
}
for(int i=1;i<=m;i++)
{
int x,y,c;
cin>>x>>y>>c;
if(x>y)
swap(x,y);
addedge(x,y+n,1,c);
}
cout<<minflow()<<endl;
return ;
}
int main()
{
init();
return 0;
}
~~~~~~~~~~~~~~2015.5.12更新~~~~~~~~~~~~~~~~~
bzoj 3876
http://www.lydsy.com/JudgeOnline/problem.php?id=3876
有上下界的网络流
对于每条边: x->y 费用z
x->y c:INF w:z
s->y c:INF w:z
x->t c:1 w:0
对于每个非1的点
x->1 c:INF w:0
(相当于原来的源点和汇点
贴代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#define MAXN 2000000
#define M 500
#define INF 0x3f3f3f3f
using namespace std;
struct Edge{
int v,f,w,nxt;
}e[MAXN];
int g[M],dis[M],eid,s,t;
bool vis[M];
void addedge(int u,int v,int f,int w)
{
e[++eid].v=v;e[eid].f=f,e[eid].w=w,e[eid].nxt=g[u];
g[u]=eid;
e[++eid].v=u;e[eid].f=0,e[eid].w=-w,e[eid].nxt=g[v];
g[v]=eid;
}
int pree[M],prev[M];
bool findPath()
{
queue<int >q;
q.push(s);
memset(dis,INF,sizeof(dis));
vis[s]=true;
dis[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]>dis[u]+e[i].w)
{
dis[e[i].v]=dis[u]+e[i].w;
pree[e[i].v]=i;
prev[e[i].v]=u;
if(!vis[e[i].v])
{
vis[e[i].v]=true;
q.push(e[i].v);
}
}
vis[u]=false;
}
if(dis[t]<INF)
return true;
return false;
}
int augment()
{
int u=t,delta=INF;
while(u!=s)
{
delta=min(delta,e[pree[u]].f);
u=prev[u];
}
u=t;
while(u!=s)
{
e[pree[u]].f-=delta;
e[pree[u]^1].f+=delta;
u=prev[u];
}
return dis[t]*delta;
}
int minflow()
{
int ret=0;
while(findPath())
{
ret+=augment();
}
return ret;
}
int n;
void init()
{
scanf("%d",&n);
eid=1,s=350,t=s+1;
for(int i=1;i<=n;i++)
{
int m,x,y;
scanf("%d",&m);
for(int j=1;j<=m;j++)
{
scanf("%d%d",&x,&y);
addedge(i,x,INF,y);
addedge(s,x,1,y);
}
addedge(i,t,m,0);
if(i!=1)
addedge(i,1,INF,0);
}
cout<<minflow()<<endl;
}
int main()
{
init();
return 0;
}
bzoj 1059
http://www.lydsy.com/JudgeOnline/problem.php?id=1059
对于可行的行列建边
跑最大流
其实是二分图。。。。
贴代码:
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f
#define MAXN 800
using namespace std;
int n;
int eid;
int g[MAXN];
struct Edge{
int v,f,nxt;
}e[1000000];
void addedge(int u,int v,int c)
{
e[++eid].v=v;
e[eid].f=c;
e[eid].nxt=g[u];
g[u]=eid;
e[++eid].v=u;
e[eid].f=0;
e[eid].nxt=g[v];
g[v]=eid;
}
int dis[MAXN],s,t;
bool vis[MAXN];
queue<int >q;
inline bool bfs()
{
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
while(!q.empty())
q.pop();
q.push(s);
vis[s]=true;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&!vis[e[i].v])
{
vis[e[i].v]=true;
q.push(e[i].v);
dis[e[i].v]=dis[u]+1;
}
}
return vis[t];
}
inline int dfs(int u,int delta)
{
if(u==t)
return delta;
else
{
int ret=0;
for(int i=g[u];delta&&i;i=e[i].nxt)
if(e[i].f&&dis[e[i].v]==dis[u]+1)
{
int dd=dfs(e[i].v,min(e[i].f,delta));
e[i].f-=dd;
e[i^1].f+=dd;
ret+=dd;
delta-=dd;
}
if(!ret) dis[u]=-4;
return ret;
}
}
inline int maxflow()
{
int ret=0;
while(true)
{
bfs();
if(!vis[t])return ret;
ret+=dfs(s,INF);
}
}
void init()
{
cin>>n;
eid=1;
s=2*n+10,t=s+1;
memset(g,0,sizeof(g));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int x;
scanf("%d",&x);
if(x)
addedge(i,n+j,1);
}
for(int i=1;i<=n;i++)
{
addedge(s,i,1);
addedge(i+n,t,1);
}
int ans=maxflow();
if(ans==n)
cout<<"Yes\n";
else
cout<<"No\n";
return ;
}
int T;
int main()
{
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
init();
}
return 0;
}
~~~~~~~~~~~~~~~~~~2015.5.17更新~~~~~~~~~~~~~~~~~~~~~~~~~~
bzoj 2039
http://www.lydsy.com/JudgeOnline/problem.php?id=2039
最小割
通过求补集思想,就是求最少的亏损
S->i C : s[i](关系中从i连出去的花费总和
对于点对( i, j )
i->j C: 2*val[i][j]
i->T C: a[i]
答案即sum-maxflow
贴代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define M 1050
#define MAXN 2000000
using namespace std;
int g[M],dis[M],eid,n,m,s,t;
bool vis[M];
struct EDge{
int v,f,nxt;
}e[MAXN];
void addedge(int u,int v,int f)
{
e[++eid].f=f,e[eid].v=v,e[eid].nxt=g[u];
g[u]=eid;
e[++eid].f=0,e[eid].v=u,e[eid].nxt=g[v];
g[v]=eid;
}
bool bfs()
{
queue<int >q;
q.push(s);
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[s]=0;
vis[s]=true;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f&&!vis[e[i].v])
{
dis[e[i].v]=dis[u]+1;
vis[e[i].v]=true;
q.push(e[i].v);
}
}
// cout<<vis[t]<<endl;
return vis[t];
}
int dfs(int u,int delta)
{
if(u==t)
return delta;
int ret=0;
for(int i=g[u];i&δi=e[i].nxt)
if(e[i].f&&dis[e[i].v]==dis[u]+1)
{
int dd=dfs(e[i].v,min(delta,e[i].f));
e[i].f-=dd;
e[i^1].f+=dd;
delta-=dd;
ret+=dd;
}
if(!ret)
dis[u]=-3;
// cout<<ret<<endl;
return ret;
}
int maxflow()
{
int ret=0;
// cout<<ret<<endl;
while(bfs())
{
// cout<<ret<<endl;
ret+=dfs(s,0x3f3f3f);
// cout<<ret<<endl;
}
return ret;
}
int val[M][M],sm[M],sum,a[M];
void init()
{
eid=1;
scanf("%d",&n);
s=n+10,t=s+1;
for(int i=1;i<=n;i++)
cin>>a[i],addedge(i,t,a[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&val[i][j]);
sm[i]+=val[i][j];
sum+=val[i][j];
}
for(int i=1;i<=n;i++)
addedge(s,i,sm[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j&&val[i][j]>0)
addedge(i,j,2*val[i][j]);
int ans =maxflow();
cout<<sum-ans<<endl;
}
int main()
{
init();
return 0;
}
bzoj 2324
http://www.lydsy.com/JudgeOnline/problem.php?id=2324
费用流
先floyd预处理dis[k][i][j]表示i到j仅仅经过小于等于k的点的最短路
拆点
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#define M 1000
#define MAXN 2000000
#define INF 0x3f3f3ff
using namespace std;
int g[M],dis[M],eid,s,t,n,K,m;
bool vis[M];
int dist[330][330][330],map[330][330];
struct Edge
{
int v,f,nxt,w;
} e[MAXN];
void addedge(int u,int v,int f,int w)
{
e[++eid].f=f,e[eid].v=v,e[eid].nxt=g[u],e[eid].w=w;
g[u]=eid;
e[++eid].f=0;
e[eid].v=u,e[eid].nxt=g[v],e[eid].w=-w;
g[v]=eid;
}
int prev[M],pree[M];
bool findPath()
{
queue<int >q;
memset(dis,0x3f3f3f,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[s]=0;
vis[s]=true;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=g[u]; i; i=e[i].nxt)
if(e[i].f&&dis[e[i].v]>dis[u]+e[i].w)
{
dis[e[i].v]=dis[u]+e[i].w;
pree[e[i].v]=i;
prev[e[i].v]=u;
if(!vis[e[i].v])
{
vis[e[i].v]=true;
q.push(e[i].v);
}
}
vis[u]=false;
}
return dis[t]<0x3f3f3f;
}
int augment()
{
int u=t,delta=INF;
while(u!=s)
{
delta=min(delta,e[pree[u]].f);
u=prev[u];
}
u=t;
while(u!=s)
{
e[pree[u]].f-=delta;
e[pree[u]^1].f+=delta;
u=prev[u];
}
return delta*dis[t];
}
int minflow()
{
int ret=0;
while(findPath())
{
ret+=augment();
}
return ret;
}
void init()
{
cin>>n>>m>>K;
memset(map,0x7f,sizeof(map));
for(int i=1; i<=m; i++)
{
int u,v,l;
cin>>u>>v>>l;
map[u][v]=map[v][u]=min(map[u][v],l);
}
eid=1,s=2*n+10,t=s+1;
addedge(s,0,K,0);
for(int i=1; i<=n; i++)
addedge(i,t,1,0),addedge(s,i+n,1,0);
for ( int k = 0 ; k <= n ; k ++ )
for ( int i = 0 ; i <= n ; i ++ )
for ( int j = 0 ; j <= n ; j ++ )
{
if ( map[ i ][ k ] < INF && map[ k ][ j ] < INF )
{
map[ i ][ j ] = min( map[ i ][ k ] + map[ k ][ j ] , map[ i ][ j ] ) ;
}
if(k==j&&i<j&&map[i][j]<INF)
addedge(i==0 ? 0 : i+n,j, INF, map[i][j]);
}
int ans=minflow();
cout<<ans<<endl;
}
int main()
{
init();
return 0;
}