期末考试也快结束了,抽个空补个题做做 = =!!
大体题意:
给你一个无向图,任意两个顶点都是双连通的,给你e个 必须走的边,和每个边的权值t,问最少多少权值恰好完全经过这e个必须走的边。
思路:
最短恰好完全走过,那不就是一笔画吗,不就是欧拉通路吗,并且任意两个点都是双连通,肯定能构造出欧拉通路来。
先用vector数组 在建立这张无向图,然后计算出度数是奇数的顶点个数ans,答案就是 ( ans - 2) / 2,减去两头的,并且连接一条边需要消耗两个顶点,这(ans-2)/2就是答案, 最后还要加上e 因为之前算的是 连接多个连通图的边数,e是需要走的边数,两者相加就是最后结果。
但要注意: ans 可能会是0,这样算出来答案是负数, 比如 1-2 2-3 3-1,这是一个环,并没有奇度顶点,ans是0,但这种情况 你随便选个起点 随便选个终点就好了,所以当ans 小于2 时 直接给他赋值为0就好了。
最后一点说的是就是 用dfs 计算 每一个联通块奇度顶点的个数,没啥好说 的 发现vector数组中 对应的G是奇数,递归加就可以了。
还有一个要注意的。在计算每个联通块奇度顶点个数时,如果小于2,那么应直接赋值为2,还是那个环, 环随便选个起点和终点,奇度顶点个数就是2了。
详细见代码,可能说的有点乱。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 1000 + 10;
int v,t,e;
vector<int>g[maxn];
int vis[maxn];
int cnt;
int dfs(int k){
if (vis[k])return 0;
int ans = 0;
vis[k] = 1;
int tmp = (int)g[k].size();
if (tmp % 2 == 1)++ans;
for (int i = 0; i < (int)g[k].size(); ++i){
ans += dfs(g[k][i]);
}
return ans;
}
int main(){
while(scanf("%d%d%d",&v,&e,&t) == 3 && (v || t || e)){
for (int i = 0; i <= v; ++i){
g[i].clear();
}
memset(vis,0,sizeof vis);
for (int i = 0; i < e; ++i){
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
int ans = 0;
for (int i = 1; i <= v; ++i){
if (!vis[i] && !g[i].empty())
ans += max(dfs(i),2);
}
int rmp = (ans < 2 ? 0 : (ans-2) / 2);
printf("Case %d: %d\n",++cnt,t*(rmp + e));
}
return 0;
}