hdu4975--dinic算法(1)

来源:互联网 发布:深圳公务员 知乎 编辑:程序博客网 时间:2024/05/21 07:58

好像还能用isap和矩阵dp的,不过我没咋闹明白isap,分层能看懂后面就完全看不懂了,等今天晚上看懂了在写一个用isap做这道题的方法。嗯,立flag;
题意:给出 行数m和列数n,和各行各列的和,求这个矩阵可能的排列,不同的结果不同的输出,我都写到注释上面了。
方法:dinic,就是ek算法的增强版,先以源点为0,然后对整个网络进行分层,一层一层的分,分完层在进行dfs,跑一个while,不断的对残余网络分层,搜索,知道分层分不了了,也就是说到不了终点了就完事。
思路是不难理解的,见图的思路很值得学习,
注意点1 有一个弧优化,就是在进行dfs的时候,这样dfs就可以用while了,试想dfs的对树的搜索,如果用这个方法,就可以在达到目的之前对 左,中,右进行遍历。不然只会返回一个结果,
2 在对 残残残残残余网络之后见图 在判断 路径的大小,这样就会很省时间

#include <queue>#include <vector>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <iostream>#include <algorithm>#include <functional>const int maxn=2000;using namespace std;typedef long long ll;struct edge{int to,cap,rev;edge(int a,int b,int c){to=a,cap=b,rev=c;}//分别是目的地,记录反向边的坐标,和容量;};vector<edge>G[maxn];vector<int>G1[maxn];bool vis[maxn];int cengci[maxn];int n,m;int itr[maxn];void addedge(int from,int to,int value){   G[from].push_back((edge){to,value,G[to].size()});    G[to].push_back((edge){from,0,G[from].size()-1});}void add_edge(int from,int to){   G1[from].push_back(to);}void bfs(int s){    queue<int>q;     q.push(s);     memset(cengci,-1,sizeof(cengci));     cengci[s]=0;//这和上面一行都是分层必要的初始化;     while(!q.empty())     {   int u=q.front();     q.pop();        for(int i=0;i<G[u].size();i++)         {   edge &s=G[u][i];             if(cengci[s.to]<0&&s.cap>0)               {cengci[s.to]=cengci[u]+1;//分层;               q.push(s.to);}         }     }}int dfs(int s,int t,int f){   //int flow;   if(s==t) return f;//dfs结束的条件   for(int &i=itr[s];i<G[s].size();i++)   {  edge &w=G[s][i];       if(w.cap>0&&cengci[w.to]>cengci[s])       {  int d=dfs(w.to,t,min(w.cap,f));            if(d>0)            {   w.cap-=d;                G[w.to][w.rev].cap+=d;//反向边,自己画一个二维数组就理解了。g就是二位数组。                return d;            }       }   }return 0;}int max_flow(int s,int t){  int INF=0x3f3f3f3f;int flow=0;int cas=1;   while(1)   {   bfs(s);     memset(itr,0,sizeof(itr));      if(cengci[t]<0)        {  //printf("%d!!! %d\n",t,cengci[t]);            //printf("%d!!!!\n",cas++);            return flow;}      int l;//=dfs(s,t,INF);       while(l=dfs(s,t,INF))//多次进行dfs,而不是一次分层然后一次dfs,         flow+=l;   }}bool judge_dfs(int x,int val){   vis[x]=1;    for(int i=0;i<G1[x].size();i++)    {   int t=G1[x][i];        if(t==val) continue;//不找反向边。反向边一定能成为环所以你在逗我??        if(vis[t]) return 1;//确定已经找到环了,因为vis被预定就是说明是环了        if(judge_dfs(t,x)) return 1;//继续dfs,把后继节点的t变成左边的x,这样在下一个dfs中如果t==val就是说明        //他的后继节点是前驱结点,所以就是环咯。    }    vis[x]=0;    return 0;}bool judge(){   memset(vis,0,sizeof(vis));   for(int i=0;i<=m+n+1;i++)   {   for(int j=0;j<G[i].size();j++)         {edge &e=G[i][j];         if(e.cap>0)//你看你看,如果在残余网络中边还存在,那么就见图,新建的图已经找不到一条增广路径了555;          add_edge(i,e.to);}   }    for(int i=0;i<=n;i++)       if(judge_dfs(i,-1)) return 1;//第二个参数设定成多少都行,只要不在 点的范围里。。就是钦定的边,就是说,如果判断某个具体的点能不能       //构成环。    return 0;}int main(){    int T;    int a,b,t=1;    scanf("%d",&T);    while(T--)    {  scanf("%d%d",&n,&m);       for(int i=0;i<maxn;i++)       {  G[i].clear();          G1[i].clear();       }       int sum1=0,sum2=0,sum=0;        for(int i=1;i<=n;i++)          {scanf("%d",&a);         addedge(0,i,a);     sum+=a,sum1+=a;//把所有杭上的点给加了     //也就是左边的原点到左边一排的最大流。         }         for(int j=n+1;j<=m+n;j++)         {   scanf("%d",&a);            addedge(j,m+n+1,a);            sum2+=a;//右边的最大流;         }         if(sum1!=sum2)         {printf("Case #%d: So naive!\n",t++);//不能成立,数据有问题啊哈哈          continue;         }          for(int i=1;i<=n;i++)            for(int j=1+n;j<=m+n;j++)          {  addedge(i,j,9);          }         int ans=max_flow(0,m+n+1);          //printf("%d   %d*******\n",ans,sum);        if(ans!=sum)            printf("Case #%d: So naive!\n",t++);//最大流跑不到和,不能成立。        else        {     if(judge())             printf("Case #%d: So young!\n",t++);//好多种类方法。             //在这个图中             //这个图表示的意思 就是各个行和和列和相互制约关系的成立。             //而这个图中有环,就说明了把每个边权加一个少一个都是没关系的。这部就有多种情况了嘛。             else                printf("Case #%d: So simple!\n",t++);//只有一种情况,费了好大劲做出来。-。-好简单啊。        }    }    return 0;}
0 0
原创粉丝点击