题意:以0为起点的一张带权有向图,保证联通,有环的话环里的边权可以忽略,有重边,求从0开始遍历整张图的最小代价。
题解:有环而且可以忽略,tarjan缩点再建新图就可以,然后贪心的从每个点的入边里选一条最小的连上。(其实就考了一个tarjan的模板)
考试的时候一直在想最小生成树,但是最小生成树只适用于无向图,无向图并不适用,反例很好举。结果wa10,直接导致这次考试崩掉,以后一定要注意每种算法的适用条件。
真的很水,考完试5分钟A掉。。。。。。。。考试的时候为什么打不出来呢。。。(想扇自己)
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> #include<cstring> #define ll long long using namespace std; struct node { int x,to,nxt,w; }h[200100]; struct h { int x,to,nxt,w; }t[200100]; int n,m,rt,mm,top,cnt,num,dfn[50010],low[50010],s[50010],whos[50010],tot,nxt[200100],fa[50010],tet,nx[200100],ans[50010],in[50010]; bool is[50010]; ll as; int read() { int aa=0,bb=1;char cc=getchar(); while(cc>'9'||cc<'0'){if(cc=='-') bb=-1;cc=getchar();} while(cc<='9'&&cc>='0'){aa=aa*10+cc-'0';cc=getchar();} return aa*bb; } void init() { top=as=cnt=num=tot=tet=0; memset(nxt,0,sizeof(nxt)); memset(nx,0,sizeof(nx)); memset(ans,0x5f,sizeof(ans)); for(int i=1;i<=n;i++){ dfn[i]=0;low[i]=0;is[i]=0;in[i]=0; } } int min(int x,int y) { return x<y?x:y; } void add(int x,int y,int w) { h[++tot].to=y; h[tot].w=w; h[tot].nxt=nxt[x]; nxt[x]=tot; h[tot].x=x; } void insert(int x,int y,int w) { t[++tet].to=y; t[tet].w=w; t[tet].nxt=nx[x]; nx[x]=tet; t[tet].x=x; } void tarjan(int x) { dfn[x]=low[x]=++cnt; s[++top]=x;is[x]=1; for(int i=nx[x];i;i=t[i].nxt){ int y=t[i].to; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); } else if(is[y]) low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]){ num++; while(1){ int tmp=s[top--]; is[tmp]=0; whos[tmp]=num; if(tmp==x) break; } } } bool cmp(node a,node b) { return a.w<b.w; } void dfs(int x) { for(int i=nxt[x];i;i=h[i].nxt){ int y=h[i].to;//cout<<h[i].w<<endl; ans[y]=min(ans[y],h[i].w); dfs(y); } } int main() { while(1){ n=read();m=read(); init(); if(n==0&&m==0) break; int u,v,w; for(int i=1;i<=m;i++){ u=read();v=read();w=read(); u++,v++; insert(u,v,w); } for(int i=1;i<=n;i++){ if(!dfn[i]) tarjan(i); } for(int i=1;i<=n;i++){ for(int j=nx[i];j;j=t[j].nxt){ int y=t[j].to; if(whos[y]!=whos[i]){ add(whos[i],whos[y],t[j].w); in[whos[y]]++; } } } for(int i=1;i<=num;i++){ if(!in[i]){ rt=i; break; } } dfs(rt);ans[rt]=0; for(int i=1;i<=num;i++){ as+=ans[i]; } printf("%lld\n",as); } return 0; }