LuoguP2764 最小路径覆盖问题(最大流)

题目描述

«问题描述:

给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。提示:设V={1,2,.... ,n},构造网络G1=(V1,E1)如下:

每条边的容量均为1。求网络G1的( 0 x , 0 y )最大流。

«编程任务:

对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。

输入输出格式

输入格式:

件第1 行有2个正整数n和m。n是给定有向无环图G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。

输出格式:

从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。

解题思路:

转换一下思路,需要覆盖,那么最多就需要点数条路径。

然后发现,有些路径可以合并,而且每合并一个点集,就少一条路径。

那么什么样的点可以合并呢,就是一条边相连的。

那么将一个点分裂成两个一个用于接受合并,一个用来提供合并。

相连的点,从起点的提供指向终点的接受,流量为$inf$

每个点都可以是起点终点所以向源汇点连$1$的边。

最大流最后拿n减掉就好了。

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 const int oo=0x3f3f3f3f;
  5 namespace stb{
  6     template<class tnt>
  7     class queue{
  8         public:
  9             queue(){h=1,t=0;}
 10             int nxt(int x){if(x+1==1000000)return 1;return x+1;}
 11             void push(tnt x){t=nxt(t);l[t]=x;return ;}
 12             bool empty(void){return nxt(t)==h;}
 13             tnt front(void){return l[h];}
 14             void clear(void){h=1,t=0;}
 15             void pop(void){h=nxt(h);}
 16         private:
 17             tnt l[1000000];
 18             int h,t;
 19     };
 20 };
 21 struct pnt{
 22     int hd;
 23     int now;
 24     int lyr;
 25     int nxt;
 26     bool nos;
 27 }p[1000];
 28 struct ent{
 29     int twd;
 30     int lst;
 31     int vls;
 32 }e[100000];
 33 int cnt;
 34 int n,m;
 35 int s,t;
 36 stb::queue<int>Q;
 37 void ade(int f,int t,int v)
 38 {
 39     cnt++;
 40     e[cnt].twd=t;
 41     e[cnt].vls=v;
 42     e[cnt].lst=p[f].hd;
 43     p[f].hd=cnt;
 44     return ;
 45 }
 46 bool Bfs(void)
 47 {
 48     Q.clear();
 49     for(int i=1;i<=n*2+2;i++)
 50         p[i].lyr=0;
 51     p[s].lyr=1;
 52     Q.push(s);
 53     while(!Q.empty())
 54     {
 55         int x=Q.front();
 56         Q.pop();
 57         for(int i=p[x].hd;i;i=e[i].lst)
 58         {
 59             int to=e[i].twd;
 60             if(p[to].lyr==0&&e[i].vls>0)
 61             {
 62                 p[to].lyr=p[x].lyr+1;
 63                 if(to==t)
 64                     return true;
 65                 Q.push(to);
 66             }
 67         }
 68     }
 69     return false;
 70 }
 71 int Dfs(int x,int fll)
 72 {
 73     if(x==t)
 74         return fll;
 75     for(int &i=p[x].now;i;i=e[i].lst)
 76     {
 77         int to=e[i].twd;
 78         if(p[to].lyr==p[x].lyr+1&&e[i].vls>0)
 79         {
 80             int ans=Dfs(to,std::min(fll,e[i].vls));
 81             if(ans>0)
 82             {
 83                 e[i].vls-=ans;
 84                 e[((i-1)^1)+1].vls+=ans;
 85                 p[x].nxt=to;
 86                 if(x!=s)
 87                     p[to-n].nos=true;
 88                 return ans;
 89             }
 90         }
 91     }
 92     return 0;
 93 }
 94 void Dinic(void)
 95 {
 96     int ans=0;
 97     while(Bfs())
 98     {
 99         for(int i=1;i<=2*n+2;i++)
100             p[i].now=p[i].hd;
101         int dlt;
102         while(dlt=Dfs(s,oo))
103             ans+=dlt;
104     }
105     for(int i=1;i<=n;i++)
106     {
107         if(!p[i].nos)
108         {
109             for(int j=i;j!=t-n&&j>0;j=p[j].nxt-n)
110                 printf("%d ",j);
111             puts("");
112         }
113     }
114     printf("%d\n",n-ans);
115     return ;
116 }
117 int main()
118 {
119     scanf("%d%d",&n,&m);
120     s=n*2+1,t=n*2+2;
121     for(int i=1;i<=n;i++)
122     {
123         ade(s,i,1);
124         ade(i,s,0);
125         ade(i+n,t,1);
126         ade(t,n+i,0);
127     }
128     for(int i=1;i<=m;i++)
129     {
130         int a,b;
131         scanf("%d%d",&a,&b);
132         ade(a,b+n,oo);
133         ade(b+n,a,0);
134     }
135     Dinic();
136     return 0;
137 }

 

猜你喜欢

转载自www.cnblogs.com/blog-Dr-J/p/10205237.html