zoukankan      html  css  js  c++  java
  • BZOJ2893:征服王(费用流)

    Description

    虽然春希将信息传递给了雪菜,但是雪菜却好像完全不认得春希了。心急如焚的春希打开了第二世代机能,对雪菜的脑内芯片进行了直连-hack。
    进入到雪菜内部的春希发现(这什么玩意。。),雪菜的脑部结构被分成了n个块落,并且一些块落之间被有向边连接着。由于四分五裂的脑部,雪菜关于春希的记忆也完全消失,春希为了恋人,启动了inversionprocess.
    在inversion process中,要想使雪菜回到正常状态,需要纳米机器人的帮助。纳米机器人可以从任意一个可以作为起点的块落出发进行修复,也可以在任意一个可以作为终点的块落结束修复(并不是到了某个终点就一定要停止)。春希希望所有的节点都能被修复(只要纳米机器人到过该点就算修复过),这样才能让雪菜重获新生。
    作为纳米机器人1号的你能帮助春希算算至少需要多少个机器人才能拯救雪菜吗?
    当然,如果无论如何都无法使得春希的愿望被满足的话,请输出”no solution”(不包括引号)

    Input

    题目包含多组数据
    第1行有一个正整数t,表示数据的组数。
    第2行有两个正整数n、m,a,b,分别表示块落的数量、有向边的数量、起点的数量、终点的数量。
    第3行有a个正整数,表示可以作为起点的块落。
    第4行有b个正整数,表示可以作为终点的块落。
    第5行至第m+4行,每行有两个正整数u、v,表示能从编号为u的块落到编号为v的块落。
    之后以此类推。

    Output

    输出共有t行,每行输出对应数据的答案。

    Sample Input

    2
    2 1 1 1
    1
    2
    2 1
    3 2 3 3
    1 2 3
    1 2 3
    1 2
    1 3

    Sample Output

    no solution
    2
    【数据规模和约定】
    对于30%的数据,满足n <= 10, m <= 100。
    对于60%的数据,满足n <= 200, m <= 5000。
    对于100%的数据,满足t<=10,n <= 1000, m <= 10000。

    Solution

    打死白学家

    首先第一感觉这个题很像最小路径覆盖……但他并不是一个$DAG$。所以我们自己动手丰衣足食把它缩成一个$DAG$。

    现在变成了一个多起点多终点的最小路径覆盖问题。我们首先把一个点拆成$u$和$u'$,并且$u$连向$u'$一条流量为$1$,费用为1的边。

    然后原图的边就$u'$连向$v$一条流量为$INF$,费用为$0$的边。

    源点$S$向图中的起点$s$连流量为$INF$,费用为$0$的边,终点$t'$向图中的汇点$E$流量为$INF$,费用为$0$的边。

    跑一边最大费用最大流。如果费用为点数那么说明每个点都经过了,答案为增广次数。

    否则无解。

    Code

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<queue>
      5 #define N (10009)
      6 using namespace std;
      7 
      8 struct Edge{int to,next,flow,cost;}edge[N*100];
      9 int DFN[N],Low[N],Stack[N],ID[N],Vis[N],top,dfs_num,id_num;
     10 int T,n,m,A,B,a[N],b[N],u[N*10],v[N*10],x,INF,s,e=10000;
     11 int dis[N],pre[N],vis[N];
     12 int head[N],num_edge;
     13 queue<int>q;
     14 
     15 void Clear()
     16 {
     17     memset(head,0,sizeof(head));
     18     memset(DFN,0,sizeof(DFN));
     19     memset(Low,0,sizeof(Low));
     20     memset(ID,0,sizeof(ID));
     21     memset(Vis,0,sizeof(Vis));
     22     num_edge=top=dfs_num=id_num=0;
     23 }
     24 
     25 void add(int u,int v,int l,int c)
     26 {
     27     edge[++num_edge].to=v;
     28     edge[num_edge].next=head[u];
     29     edge[num_edge].flow=l;
     30     edge[num_edge].cost=c;
     31     head[u]=num_edge;
     32 }
     33 
     34 bool SPFA(int s,int e)
     35 {
     36     memset(dis,0x7f,sizeof(dis));
     37     memset(pre,-1,sizeof(pre));
     38     dis[s]=0; q.push(s); vis[s]=1;
     39     while (!q.empty())
     40     {
     41         int x=q.front(); q.pop();
     42         for (int i=head[x]; i; i=edge[i].next)
     43             if (edge[i].flow && dis[x]+edge[i].cost<dis[edge[i].to])
     44             {
     45                 dis[edge[i].to]=dis[x]+edge[i].cost;
     46                 pre[edge[i].to]=i;
     47                 if (!vis[edge[i].to])
     48                 {
     49                     vis[edge[i].to]=1;
     50                     q.push(edge[i].to);
     51                 }
     52             }
     53         vis[x]=0;
     54     }
     55     return dis[e]!=INF;
     56 }
     57 
     58 void MCMF(int s,int e)
     59 {
     60     int fee=0,ans=0;
     61     while (SPFA(s,e))
     62     {
     63         if (dis[e]==0) break;
     64         else ans++;
     65         int d=INF;
     66         for (int i=e; i!=s; i=edge[((pre[i]-1)^1)+1].to)
     67             d=min(d,edge[pre[i]].flow);
     68         for (int i=e; i!=s; i=edge[((pre[i]-1)^1)+1].to)
     69         {
     70             edge[pre[i]].flow-=d;
     71             edge[((pre[i]-1)^1)+1].flow+=d;
     72         }
     73         fee+=d*dis[e];
     74     }
     75     if (-fee==id_num) printf("%d
    ",ans);
     76     else puts("no solution");
     77 }
     78 
     79 void Tarjan(int x)
     80 {
     81     DFN[x]=Low[x]=++dfs_num;
     82     Stack[++top]=x; Vis[x]=1;
     83     for (int i=head[x]; i; i=edge[i].next)
     84         if (!DFN[edge[i].to])
     85         {
     86             Tarjan(edge[i].to);
     87             Low[x]=min(Low[x],Low[edge[i].to]);
     88         }
     89         else if (Vis[edge[i].to])
     90             Low[x]=min(Low[x],DFN[edge[i].to]);
     91     if (DFN[x]==Low[x])
     92     {
     93         ID[x]=++id_num; Vis[x]=0;
     94         while (Stack[top]!=x)
     95         {
     96             ID[Stack[top]]=id_num;
     97             Vis[Stack[top--]]=0;
     98         }
     99         top--;
    100     }
    101 }
    102 
    103 int main()
    104 {
    105     memset(&INF,0x7f,sizeof(INF));
    106     scanf("%d",&T);
    107     while (T--)
    108     {
    109         Clear();
    110         scanf("%d%d%d%d",&n,&m,&A,&B);
    111         for (int i=1; i<=A; ++i) scanf("%d",&a[i]);
    112         for (int i=1; i<=B; ++i) scanf("%d",&b[i]);
    113         for (int i=1; i<=m; ++i) scanf("%d%d",&u[i],&v[i]), add(u[i],v[i],0,0);
    114         for (int i=1; i<=n; ++i) if (!DFN[i]) Tarjan(i);
    115         memset(head,0,sizeof(head)); num_edge=0;
    116         for (int i=1; i<=A; ++i)
    117             add(s,ID[a[i]],INF,0), add(ID[a[i]],s,0,0);
    118         for (int i=1; i<=B; ++i)
    119             add(ID[b[i]]+5000,e,INF,0), add(e,ID[b[i]]+5000,0,0);
    120         for (int i=1; i<=m; ++i)
    121             if (ID[u[i]]!=ID[v[i]])
    122                 add(ID[u[i]]+5000,ID[v[i]],INF,0), add(ID[v[i]],ID[u[i]]+5000,0,0);
    123         for (int i=1; i<=id_num; ++i)
    124         {
    125             add(i,i+5000,1,-1); add(i+5000,i,0,1);
    126             add(i,i+5000,INF,0); add(i+5000,i,0,0);
    127         }
    128         MCMF(s,e);
    129     }
    130 }
  • 相关阅读:
    Java 线程间通信 —— 等待 / 通知机制
    Java 线程基础
    Java 内存模型
    Java 并发机制底层实现 —— volatile 原理、synchronize 锁优化机制、原子操作
    优秀程序员的博客有哪些?
    程序员五一被拉去相亲,结果彻底搞懂了HTTP常用状态码
    【Redis破障之路】三:Redis单线程架构
    【Redis破障之路】一:强大的Redis
    MySQL提升笔记(4)InnoDB存储结构
    MySQL提升笔记(3)日志文件详解
  • 原文地址:https://www.cnblogs.com/refun/p/10289275.html
Copyright © 2011-2022 走看看