zoukankan      html  css  js  c++  java
  • POJ 3921(费用流+拆点)

    题目大意:
    一个有向图有N个点,M条边。现在要求删掉最少的点,使得不存在从1号点到N号点的长度<=K的路径(不能直接删掉1号点或N号点)。求最少删除多少点。

    PS:边是有向的

    思路:费用流+拆点(话说dfs貌似也能过,毕竟点那么少)
    把每个点拆成两个点,a1和a2,中间连一条容量为1,费用为0的边(注意起点和终点的处理)
    对于每一条数据中的有向边a-->b,连一条a2-->b1的容量为INF,费用为1的边

    剩下的就是跑费用流啦~当最短路大于K停止

     

    PS:这个算法是错的,请看这组数据

    10 11 5
    1 2 
    2 3
    3 4
    4 5
    5 10
    2 9
    1 6
    6 7
    7 8
    8 9
    9 10

    图:

     

     正解应该是迭代加深搜索吧。不知道还有哪位神犇有神级的思路!

    View Code
     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #define N 200
     5 #define M 500000
     6 #define INF 100000000
     7 using namespace std;
     8 int head[N],next[M],len[M],w[M],to[M],cnt,n,m,k,S,T,dis[N],q[M<<4],pre[M];
     9 bool vis[N];
    10 void add(int u,int v,int c,int wp)
    11 {
    12     to[cnt]=v; len[cnt]=c; w[cnt]=wp; next[cnt]=head[u]; head[u]=cnt++;
    13     to[cnt]=u; len[cnt]=0; w[cnt]=-wp; next[cnt]=head[v]; head[v]=cnt++;
    14 }
    15 void read()
    16 {
    17     memset(head,-1,sizeof head);cnt=0;
    18     for(int i=2;i<n;i++) add(i,i+n,1,0);
    19     add(1,1+n,INF,0); add(n,n+n,INF,0);//拆点 
    20     for(int i=1,a,b;i<=m;i++)
    21     {
    22         scanf("%d%d",&a,&b);
    23         add(a+n,b,INF,1);
    24     }
    25     S=1; T=n+n;
    26 }
    27 bool spfa()
    28 {
    29     for(int i=0;i<=T;i++) dis[i]=INF;
    30     int h=1,t=2,sta;
    31     q[1]=S; vis[S]=true; dis[S]=0; pre[S]=-1;
    32     while(h<t)
    33     {
    34         sta=q[h++];
    35         vis[sta]=false;
    36         for(int i=head[sta];~i;i=next[i])
    37             if(len[i]>0&&dis[to[i]]>dis[sta]+w[i])
    38             {
    39                 dis[to[i]]=dis[sta]+w[i];
    40                 pre[to[i]]=i;
    41                 if(!vis[to[i]])
    42                 {
    43                     vis[to[i]]=true;
    44                     q[t++]=to[i];
    45                 }
    46             }
    47     }
    48     return dis[T]!=INF;
    49 }
    50 void go()
    51 {
    52     int cs=0;
    53     while(spfa())
    54     {
    55         if(dis[T]>k) break;
    56         cs++;//printf("%d\n",cs);
    57         for(int i=T,tmp;i!=S;i=to[tmp^1])
    58         {
    59             //printf("%d\n",i);
    60             tmp=pre[i];
    61             len[tmp]-=1;
    62             len[tmp^1]+=1;
    63         }
    64     }
    65     printf("%d\n",cs);
    66 }
    67 int main()
    68 {
    69     while(scanf("%d%d%d",&n,&m,&k),n||m||k)
    70     {
    71         read();
    72         go();
    73     }
    74     return 0;
    75 }

    后记:这个才是假期最后一篇。

    没有人能阻止我前进的步伐,除了我自己!
  • 相关阅读:
    单片机就那点资源,为啥还要用RTOS?
    JVM 虚拟机参数配置
    C# 多态virtual标记重写 以及EF6 查询性能AsNoTracking
    C# HttpClient发送请求获取接口数据
    C# Socket服务端和客户端通话
    C# 生成图片验证码 图片缩略图 水印
    ADO.NET 帮助类 参数传递 存储过程 分页
    hadoop单机部署
    tengine-sticky
    redis持久化
  • 原文地址:https://www.cnblogs.com/proverbs/p/2664365.html
Copyright © 2011-2022 走看看