题目大意:一个有v个顶点的完全图,找一条经过m条指定边的最短路径。
题目分析:当每条边仅经过一次时,路径最短。给出的边可能构成若干棵树。在一棵树中,奇点个数总为偶数,若一棵树的奇点个数为0,则这棵树可以构成欧拉回路,若不为0,则必有走不到的边(每条边仅经过一次,下同)。在一棵树中,设奇点个数为n,则走不到的边数为(n-2)/2 (n-2为除去起点和终点的奇点个数),这意味着,还需要走额外的(n-2)/2条边才能将这(n-2)/2条指定的但走不到的边走完。并且,这(n-2)/2条走不到的边是不共点的,这意味着,一棵树还是多棵树是无关紧要的。但是,如果有的树中奇点个数恰为0,没有走不到的边,此时这棵树成了孤立的了,要注意这种情况。
代码如下:
# include<iostream> # include<cstdio> # include<set> # include<vector> # include<cstring> # include<algorithm> using namespace std; struct Edge { int to,nxt; }; Edge e[500000]; int n,m,t,head[1005],vis[1005],cnt,du[1005],num; set<int>s; void add(int u,int v) { e[cnt].to=v; e[cnt].nxt=head[u]; head[u]=cnt++; } void dfs(int u) { num+=(du[u]&1); for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(!vis[v]){ vis[v]=1; dfs(v); } } } int main() { int a,b,cas=0; while(scanf("%d%d%d",&n,&m,&t)&&(n+m+t)) { cnt=0; s.clear(); memset(head,-1,sizeof(head)); memset(du,0,sizeof(du)); for(int i=0;i<m;++i) { scanf("%d%d",&a,&b); add(a,b); add(b,a); s.insert(a); s.insert(b); ++du[a],++du[b]; } num=0; memset(vis,0,sizeof(vis)); for(set<int>::iterator it=s.begin();it!=s.end();++it){ if(!vis[*it]){ int temp=num; vis[*it]=1; dfs(*it); if(temp+2>num)///注意树中奇点个数为0的情况 num=temp+2; } } printf("Case %d: %d ",++cas,(max(0,(num-2)/2)+m)*t); } return 0; }