SPOJ 287 网络流最大流+二分答案 解题报告

来源:互联网 发布:对对子软件下载 编辑:程序博客网 时间:2024/06/06 00:57

NETADMIN - Smart Network Administrator

The citizens of a small village are tired of being the only inhabitants around without a connection to the Internet. After nominating the future network administrator, his house was connected to the global network. All users that want to have access to the Internet must be connected directly to the admin’s house by a single cable (every cable may run underground along streets only, from the admin’s house to the user’s house). Since the newly appointed administrator wants to have everything under control, he demands that cables of different colors should be used. Moreover, to make troubleshooting easier, he requires that no two cables of the same color go along one stretch of street.
Your goal is to find the minimum number of cable colors that must be used in order to connect every willing person to the Internet.

Input

t [the number of test cases, t<=500]
n m k [n <=500 the number of houses (the index of the admin’s house is 1)]
[m the number of streets, k the number of houses to connect]
h1 h2 … hk [a list of k houses wanting to be conected to the network, 2<=hi<=n]
[The next m lines contain pairs of house numbers describing street ends]
e11 e12
e21 e22

em1 em2
[next cases]

Output

For each test case print the minimal number of cable colors necessary to make all the required connections.

Example

Input:

2
5 5 4
2 3 4 5
1 2
1 3
2 3
2 4
3 5
8 8 3
4 5 7
1 2
1 8
8 7
1 3
3 6
3 2
2 4
2 5

Output:

2
1

这里写图片描述

[解题报告]
此题乍一看不太好考虑,不知道如何去控制同一街道内的缆线颜色各不相同。我 们不妨先尝试着建立一个网络模型出来:以第一家作为汇点 t ,K 户人家中的每 一户i 作为一个点并连边(s, i, 1),对每条街道(u, v),连边(u, v, c), (v, u, c),c=∞.这样求完最大流后每一条s-t 流均对应一户人家的缆线,而各条街道内的流量表 示有多少户人家的缆线同时穿过该街道,那么这个流量就是只考虑该条街道的时 候最少的不同颜色种数。那么答案是否就是所有街道的不同颜色种数的最大值呢?
当然不是!最大流只保证总流量最大,而不会去管每条流具体该往哪儿流,所以 这么做不一定能得到最优解。我们只要稍微修改这个模型就一定能保证得到最优 解:强制c 等于某个值limit,再对网络求最大流,如果等于K,说明用c 种不同 的颜色已经足够了;如果小于K,说明c 种还不够,还需要往高了调。同时此处 的单调性也很明显:c 越高越容易满足要求。思路一下就豁然开朗了:二分c 的 值,如果足够了就往下调,否则往上调,直到找到足够和不足够的临界值为止。
(WA了半天竟然是数组开小了…)

代码如下:

#include<cstdio>  #include<cstring> #include<string>#include<algorithm>#include<map>#include<queue>  #include<vector>using namespace std;  #define inf 0x3f3f3f3f  #define maxv 1000#define maxe 1000005 int nume=0,head[maxv],e[maxe][3];void inline adde(int i,int j,int c)  {      e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;      e[nume++][2]=c;     e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;      e[nume++][2]=0;  }  int ss,tt,n,m,k,t;  int vis[maxv],lev[maxv]; bool bfs()  {      for(int i=0;i<maxv;i++)      vis[i]=lev[i]=0;      queue<int>q;      q.push(ss);      vis[ss]=1;      while(!q.empty())      {          int cur=q.front();          q.pop();          for(int i=head[cur];i!=-1;i=e[i][1])          {              int v=e[i][0];              if(!vis[v]&&e[i][2]>0)              {                  lev[v]=lev[cur]+1;                  vis[v]=1;                  q.push(v);              }          }      }      return vis[tt];  }  int dfs(int u,int minf)  {      if(u==tt||minf==0) return minf;      int sumf=0,f;      for(int i=head[u];i!=-1&&minf;i=e[i][1])      {          int v=e[i][0];          if(lev[v]==lev[u]+1&&e[i][2]>0)          {              f=dfs(v,minf<e[i][2]?minf:e[i][2]);              e[i][2]-=f;e[i^1][2]+=f;              sumf+=f;minf-=f;          }      }      if(!sumf) lev[u]=-1;      return sumf;  }  int Dinic()  {      int sum=0;      while(bfs()) sum+=dfs(ss,inf);      return sum;  }  int a[520];struct edge{    int x,y;}ed[250010];int main(){//  freopen("in.txt","r",stdin);    for(scanf("%d",&t);t;--t)    {        scanf("%d%d%d",&n,&m,&k);        for(int i=1;i<=k;++i) scanf("%d",&a[i]);        for(int i=1;i<=m;++i) scanf("%d%d",&ed[i].x,&ed[i].y);        int l=0,r=n,ans=0;        ss=0,tt=1;        while(l<=r)        {            int mid=(l+r)>>1;            nume=0;            memset(head,-1,sizeof(head));            for(int i=1;i<=k;++i) adde(ss,a[i],1);            for(int i=1;i<=m;++i)             {                adde(ed[i].x,ed[i].y,mid);                adde(ed[i].y,ed[i].x,mid);            }            int flow=Dinic();            if(flow==k)            {                ans=mid;                r=mid-1;            }            else l=mid+1;        }        printf("%d\n",ans);    }    return 0;}

让我看到你们的双手

原创粉丝点击