UVa 12118 : Inspector's Dilemma
题目大意:
有一个有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;
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号