UVa12118:Inspector's Dilemma

来源:互联网 发布:手机淘宝店怎样发货 编辑:程序博客网 时间:2024/05/21 16:57

题目大意:

有一个有V(V<=1000)个节点的图,每两个点之间都有边连接,所有边长为T。先给出E条指定的边,找出一条最短路(起点终点随意),使这条路径经过所有给定的边。

分析:

首先想一想,要是所有的边都没有公共节点该多好。那么答案就是(E-1)*T了。可惜并不是这样,那么,我们就可以把几个有公共端点的边看成一个子图。对于一个子图,它要有一条边连接进来,再有一条边连出去(入口出口除外)。所以就想到一个方法,对于一个子图,我们要在原图中加几条边使它联通,再把他们穿起来。想到了什么?欧拉道路!对于一个子图,我们把它变成一个”一笔画”图,添加的边数加上E,再加上连接各个子图的路径就是答案!

所以算法出来了:我们先统计各个点的度数,再DFS各个子图,求出要加上的边数,再用上文的方法就是解(这里用并查集不大方便,反正题目给的范围小,DFS更快捷)。

#include <cstdio>#include <vector>#include <set>#include <cstdlib>#include <cstring>using namespace std;const int maxn=1000+20;int dgr[maxn];bool a[maxn];vector<int> pile[maxn];int dfs(int k){ int ans=0; if (dgr[k]) ans++; //奇点,增加答案 for (int i=0;i<pile[k].size();i++) {  int next=pile[k][i];  if (!a[next]) {a[next]=1;ans+=dfs(next);} } return ans;}int main(){  int x,y,v,e,t,ca=0;  while ((scanf("%d%d%d",&v,&e,&t)==3) && (v || e || t)) //注意:有可能有V不为0,而E为0的情况  {   if ((e==0) || (v==0)) {printf("Case %d: 0\n",++ca);continue;} // 特殊判断   for (int i=0;i<v;i++) pile[i].clear(); //邻接表存边   memset(dgr,0,sizeof(dgr)); //度数,因为只要奇偶性,没必要存储实际度数   set<int> node; //给定的边涉及的点   node.clear();   for (int i=0;i<e;i++)   {    scanf("%d%d",&x,&y);    dgr[x]=1-dgr[x];    dgr[y]=1-dgr[y];  //改变奇偶性    node.insert(x);    node.insert(y);    pile[x].push_back(y);    pile[y].push_back(x);   }   set<int>::iterator it;   memset(a,0,sizeof(a)); //遍历标记   int ans=e-1; //因为有n个子图时,要加n-1条路径,下面加了n个,所以-1   for (it=node.begin();it!=node.end();it++)     if (!a[*it])     {     ans++; //子图之间的路径     a[*it]=1;     int p=dfs(*it); //子图奇点数     if (p>0) ans+=(p-2)/2; //加一条边少两个奇点,一个子图可以留两个奇点作为出入口     }   printf("Case %d: %d\n",++ca,ans*t);  }  return 0;}

想想子图的问题,是不是很像tarjan呢……

0 0
原创粉丝点击