[2016-03-05][UVALive][4059][Inspector's Dilemma]

[2016-03-05][UVALive][4059][Inspector's Dilemma]
  • 时间:2016-03-05 19:37:31 星期六
  • 题目编号:UVALive 4059
  • 题目大意:一个国家有n个城市,每2个城市都有道路相连,已知从一个城市到另一个城市的时间为T,某检查工人需要检查其中E段路,问最少需要花费多少时间
  • 输入:
      • 若干组数据,以0 0 0结束
      •      每组数据:
      •         V,E,T城市数目,需要检查的路的数目,T时间
      •         接下来E行,每行2个数字,表示a b城市的道路需要检查
  • 输出:每组数据Case cntcase: ans\n
  • 分析:给定一个完全图和图上的一些边,求走完给定的边至少要走完全图上的多少条边。
  • 方法:
      •         假设有k个联通块,那么每个联通块肯定可以分开计算,
      •         然后从一个联通块到另一个联通块需要走k-1条边,
      •         对于每个联通块,如果存在欧拉回路和欧拉路径,那么一定可以一次走完
            • 如果不存在,那么就看奇度点的个数,如果个数大于2,那么就要多走 (cnt - 2)/2条边
      •         所以最后答案就是 M + sum{ (cnt-2)/2 } + k - 1(M为有边的联通块的数目)
  • 解决方法:直接计算每个联通块的边数,加上有边联通块数目,加上每个联通块奇度点的情况对应的数字      
  • 解题过程遇到问题:
      •         边数为0的情况,应该输出0
      •         有的联通块没有边的情况(单独一个点),那么这个联通块是不需要计算的

//方法1:并查集
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef long long LL;
#define CLR(x,y) memset((x),(y),sizeof((x)))
#define FOR(x,y,z) for(int (x)=(y);(x)<(z);++(x))
#define FORD(x,y,z) for(int (x)=(y);(x)>=(z);--(x))
#define FOR2(x,y,z) for((x)=(y);(x)<(z);++(x))
#define FORD2(x,y,z) for((x)=(y);(x)>=(z);--(x))



const int maxv = 1000 + 100;
vector<int> v[maxv];
int fa[maxv],cntodd[maxv];//cntodd 保存每个联通块奇度顶点的个数
void ini(int n){
        FOR(i,1,n + 1){  
                fa[i] = i;
                v[i].clear();
                cntodd[i] = 0;
        }
}
int fnd(int x){
        return x == fa[x]?x:fa[x] = fnd(fa[x]);
}
void uni(int x,int y){
        fa[fnd(x)] = fnd(y);
}
int main(){
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int V,E,T,cntcase = 0;
        while(~scanf("%d%d%d",&V,&E,&T) && (V||E||T)){
                int u1,v1;
                ini(V);
                FOR(i,0,E){
                        scanf("%d%d",&u1,&v1);
                        uni(u1,v1);
                        v[u1].push_back(v1);
                        v[v1].push_back(u1);
                }
                //计算有边联通块的数目 和 每个联通块奇度顶点的个数
                int cntfa = 0,res = 0;
                FOR(i,1,V + 1){  
                        if(fa[i] == i && v[i].size())  ++cntfa;
                        if( v[i].size() & 1)  ++cntodd[fnd(i)];
                }
                //判断每个联通块奇度顶点个数
                FOR(i,1,V + 1)  if(fa[i] == i && cntodd[i] > 2)
                        res += (cntodd[i] - 2)/2;
                //如果有效联通块的数目为0,即没有边,那么就不需要减1
                res += E + (cntfa>1? cntfa - 1:0);
                printf("Case %d: %d\n",++cntcase,res*T);
        }
    return 0;
}  

//方法2:dfs
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef long long LL;
#define CLR(x,y) memset((x),(y),sizeof((x)))
#define FOR(x,y,z) for(int (x)=(y);(x)<(z);++(x))
#define FORD(x,y,z) for(int (x)=(y);(x)>=(z);--(x))
#define FOR2(x,y,z) for((x)=(y);(x)<(z);++(x))
#define FORD2(x,y,z) for((x)=(y);(x)>=(z);--(x))



const int maxn = 1000 + 10;
const int maxedge = maxn * maxn;
int head[maxn];
int nextt[maxedge];
int endd[maxedge];
void addedge(int from,int to){
        static int q = 2;
        endd[q] = to;
        nextt[q] = head[from];
        head[from] = q++;
}
int d[maxn],vis[maxn];
void dfs(int cur,int & cntodd){
        vis[cur] = 1;
        if(d[cur] & 1)    ++cntodd;
        for(int q = head[cur];~q;q = nextt[q]){
                int v = endd[q];
                if(!vis[v])     dfs(v,cntodd);                
        }
}
//初始化
void ini(){
        memset(head,-1,sizeof(head));
        memset(nextt,-1,sizeof(nextt));
        memset(endd,-1,sizeof(endd));
        CLR(d,0);CLR(vis,0);
}
int main(){
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int V,E,T,cntcase = 0;
        while(~scanf("%d%d%d",&V,&E,&T) && (V||E||T)){
                int u1,v1;
                ini();
                FOR(i,0,E){
                        scanf("%d%d",&u1,&v1);
                        addedge(u1,v1);
                        addedge(v1,u1);
                        ++d[v1];++d[u1];
                }
                int res = E;
                FOR(i,1,V+1){
                        //计算每个有边联通块奇度点的个数.
                        if(!vis[i] && head[i] != -1){
                                ++res;
                                int cntodd = 0;
                                dfs(i,cntodd);
                                if(cntodd > 2)  res += (cntodd - 2)/2;
                        }
                }
                if(res) --res;
                printf("Case %d: %d\n",++cntcase,res*T);
        }
    return 0;
}  




来自为知笔记(Wiz)


posted on 2016-03-05 21:28  红洋  阅读(162)  评论(0)    收藏  举报

导航