UVA - 12118 Inspector's Dilemma(检查员的难题)(欧拉回路)

题意:有一个n个点的无向完全图,找一条最短路(起点终点任意),使得该道路经过E条指定的边。

分析:

1、因为要使走过的路最短,所以每个指定的边最好只走一遍,所以是欧拉道路。

2、若当前连通的道路不是欧拉道路,最好的方法是通过加边使其成为欧拉道路。

3、若该图连通,则度数为奇数的点的个数只会是偶数个(连通图性质)。

4、欧拉道路只有两个度数为奇数的点,其他点度数均为偶数。

5、使一个连通图变为欧拉道路,只需要在所有度数为奇数的点之间加边,若一个连通图度数为奇数的点有x个,则需要加边(x - 2) / 2。

6、给定的边可能组成了几个连通图(并查集判断连通图个数),将各个连通图都变成欧拉道路后,再依次连接各欧拉道路,使整个图连通,依次连接各欧拉道路的加边数为欧拉道路总数-1。

7、最后便忘了加上指定的E条边的长度。

8、注意如果没有指定边,最短路长度为0。

#pragma comment(linker, "/STACK:102400000, 102400000")
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#define Min(a, b) ((a < b) ? a : b)
#define Max(a, b) ((a < b) ? b : a)
typedef long long ll;
typedef unsigned long long llu;
const int INT_INF = 0x3f3f3f3f;
const int INT_M_INF = 0x7f7f7f7f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const ll LL_M_INF = 0x7f7f7f7f7f7f7f7f;
const int dr[] = {0, 1};
const int dc[] = {1, 0};
const int MOD = 1e9 + 7;
const double pi = acos(-1.0);
const double eps = 1e-8;
const int MAXN = 1000 + 10;
const int MAXT = 500 + 10;
using namespace std;
int fa[MAXN];
int V, E, T;
int e[MAXN];
set<int> v[MAXN];//每个点的度数
set<int> cnt;
void init(){
    for(int i = 1; i <= V; ++i){
        fa[i] = i;
        v[i].clear();
    }
    memset(e, 0, sizeof e);
    cnt.clear();
}
int Find(int v){
    return fa[v] = (fa[v] == v) ? v : Find(fa[v]);
}
int solve(){
    if(E == 0) return 0;//如果没有指定边,最短路长度为0
    for(int i = 1; i <= V; ++i){
       int len = v[i].size();
       if(len == 0) continue;
       int f = Find(i);
       cnt.insert(f);
       if(len & 1){
            ++e[f];
       }
    }
    int ans = 0;
    for(int i = 1; i <= V; ++i){
        if(e[i]){
            ans += (e[i] - 2) / 2;
        }
    }
    return (ans + (int)cnt.size() - 1 + E) * T;
}
int main(){
    int kase = 0;
    while(scanf("%d%d%d", &V, &E, &T) == 3){
        if(!V && !E && !T) return 0;
        init();
        for(int i = 0; i < E; ++i){
            int x, y;
            scanf("%d%d", &x, &y);
            v[x].insert(y);
            v[y].insert(x);
            int tx = Find(x);
            int ty = Find(y);
            if(tx < ty) fa[ty] = tx;
            else if(tx > ty) fa[tx] = ty;
        }
        printf("Case %d: %d\n", ++kase, solve());
    }
    return 0;
}

 

posted @ 2017-01-18 21:16  Somnuspoppy  阅读(273)  评论(0编辑  收藏  举报