网络流复习

2 篇文章 0 订阅

这几天做了些网络流的题,在此复习一下:

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的点的最短路

拆点

1.S->0 c=k w=0
2.i->T c=1 w=0
3.S->i+n c=1 w=0
4.i+n->j c=INF w=dis[j][i][j]
贴代码:
#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;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值