这是个水题+模板题,我就是想记录一下这道题在我的考试题中出现过
一句话题解:Tarjan缩点,然后贪心转移
其实关于这个贪心还是要提两句的,我们来证明一下这题贪心的正确性
因为这道题要求每个点都必须被到达,那么我们就可以用每一个点去转移给他的子节点,如果一个子节点有多个父节点,那你在这些父节点中选一个权值最小的,一定可以通过这条边从父节点走到子节点,不会被其他节点选择的路径影响且不会对其他节点的路径选择造成影响,所以贪心一定是正确的
说实话,用贪心,贪心的正确性要想,要证,但是如果你考试的时候实在不能严格的证明出来,但是又举不出反例,想不到其他解决方法,那有时候选择贪心得部分分也是可以的,再说了,万一贪心就是正解呢,当然了,平常做题一定要花时间去想去证明,知其然知其所以然嘛
1 #include<iostream> 2 #include<cstdio> 3 #include<stack> 4 #include<cstring> 5 #define maxn 50010 6 #define maxm 100100 7 #define ll long long 8 using namespace std; 9 int n,m,js,tot,cnt,j; 10 ll ans; 11 int head[maxn],to[maxm],xia[maxm],wh[maxm]; 12 int dfn[maxn],low[maxn],pd[maxn],ss[maxn]; 13 int h[maxn],t[maxm],x[maxm],w[maxm]; 14 int f[maxn]; 15 stack <int> s; 16 int read() 17 { 18 int e=0,f=1; 19 char ch=getchar(); 20 while(ch<'0'||ch>'9') 21 { 22 if(ch=='-') f=-1; 23 ch=getchar(); 24 } 25 while(ch>='0'&&ch<='9') {e=(e<<3)+(e<<1)+(ch-48); ch=getchar();} 26 return e*f; 27 } 28 void clear() 29 { 30 js=0; tot=0; cnt=0; j=0; ans=0; 31 while(s.empty()==false) s.pop(); 32 memset(head,0,sizeof(head)); memset(to,0,sizeof(to)); memset(xia,0,sizeof(xia)); 33 memset(wh,0,sizeof(wh)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); 34 memset(pd,0,sizeof(pd)); memset(ss,0,sizeof(ss)); memset(h,0,sizeof(h)); 35 memset(t,0,sizeof(t)); memset(x,0,sizeof(x)); memset(w,0,sizeof(w)); 36 memset(f,0x7f,sizeof(f)); 37 } 38 void add(int x,int y,int z) 39 { 40 to[++js]=y; xia[js]=head[x]; wh[js]=z; head[x]=js; 41 } 42 void ADD(int a,int b,int c) 43 { 44 t[++j]=b; x[j]=h[a]; w[j]=c; h[a]=j; 45 } 46 void tarjan(int x) 47 { 48 dfn[x]=low[x]=++tot; s.push(x); pd[x]=1; 49 for(int i=head[x];i;i=xia[i]) 50 { 51 int ls=to[i]; 52 if(dfn[ls]==0) {tarjan(ls); low[x]=min(low[x],low[ls]);} 53 else if(pd[ls]==1) low[x]=min(low[x],dfn[ls]); 54 } 55 if(low[x]==dfn[x]) 56 { 57 int y; cnt++; 58 do {y=s.top(); s.pop(); pd[y]=0; ss[y]=cnt;} 59 while(y!=x); 60 } 61 } 62 void dfs(int a) 63 { 64 for(int i=h[a];i;i=x[i]) {int ls=t[i]; f[ls]=min(f[ls],w[i]); dfs(ls);} 65 } 66 int main() 67 { 68 while(1) 69 { 70 n=read(); m=read(); 71 if(n==0&&m==0) break; 72 clear(); 73 for(int i=1;i<=m;++i) {int o=read(),p=read(),q=read(); add(o+1,p+1,q);} 74 for(int i=1;i<=n;++i) 75 if(dfn[i]==0) tarjan(i); 76 for(int i=1;i<=n;++i) 77 for(int j=head[i];j;j=xia[j]) 78 { 79 int ls=to[j]; 80 if(ss[i]==ss[ls]) continue; 81 ADD(ss[i],ss[ls],wh[j]); 82 } 83 dfs(ss[1]); 84 for(int i=1;i<=cnt;++i) 85 { 86 if(ss[1]==i) continue; 87 ans+=(ll)f[i]; 88 } 89 printf("%lld ",ans); 90 } 91 return 0; 92 }