1. 程式人生 > >HDU3072 Intelligence System

HDU3072 Intelligence System

題目傳送門

有個中文版的題面...和原題稍有不同

/*
Description
“這一切都是命運石之門的選擇。” 
試圖研製時間機器的機關SERN截獲了中二科學家倫太郎發往過去的一條簡訊,並由此得知了倫太郎製作出了電話微波爐(仮)。 
為了掌握時間機器的技術,SERN總部必須儘快將這個訊息通過地下祕密通訊網路,傳達到所有分部。 
SERN共有N個部門(總部編號為0),通訊網路有M條單向通訊線路,每條線路有一個固定的通訊花費Ci。 
為了保密,訊息的傳遞只能按照固定的方式進行:從一個已知訊息的部門向另一個與它有線路的部門傳遞(可能存在多條通訊線路)。我們定義總費用為所有部門傳遞訊息的費用和。 
幸運的是,如果兩個部門可以直接或間接地相互傳遞訊息(即能按照上述方法將資訊由X傳遞到Y,同時能由Y傳遞到X),我們就可以忽略它們之間的花費。 
由於資金問題(預算都花在粒子對撞機上了),SERN總部的工程師希望知道,達到目標的最小花費是多少。

Input
多組資料,檔案以2個0結尾。 
每組資料第一行,一個整數N,表示有N個包括總部的部門(從0開始編號)。然後是一個整數M,表示有M條單向通訊線路。 
接下來M行,每行三個整數,Xi,Yi,Ci,表示第i條線路從Xi連向Yi,花費為Ci。

Output
每組資料一行,一個整數表示達到目標的最小花費。

Sample Input
3 3 
0 1 100 
1 2 50 
0 2 100 
3 3 
0 1 100 
1 2 50 
2 1 100 
2 2 
0 1 50 
0 1 100 
0 0

Sample Output
150 
100 
50 
【樣例解釋】 
第一組資料:總部把訊息傳給分部1,分部1再傳給分部2.總費用:100+50=150. 
第二組資料:總部把訊息傳給分部1,由於分部1和分部2可以互相傳遞訊息,所以分部1可以無費用把訊息傳給2.總費用:100+0=100. 
第三組資料:總部把訊息傳給分部1,最小費用為50.總費用:50.

Data Constraint
對於10%的資料,保證M=N-1 
對於另30%的資料,N ≤ 20 ,M ≤ 20 
對於100%的資料,N ≤ 50000 ,M ≤ 10^5 ,Ci ≤ 10^5 ,資料組數 ≤ 5 
資料保證一定可以將資訊傳遞到所有部門。
中文題面

 

初看此題,大概是要在一個有向圖裡找到從固定點出發遍歷每個節點的最小花費

emm...瞬間想到最小生成樹,prim大概是有的

"如果兩個部門可以直接或間接地相互傳遞訊息,我們就可以忽略它們之間的花費。"

也就是隻要有節點形成了環,那麼這些節點間通訊不要錢...

這不就tarjan縮點過後prim就好了嗎...

code了1h,搞出來了,結果發現樣例都過不了

原因是prim在無向圖裡沒辦法處理權值相同的邊

又想了想,縮點後是個DAG圖,又保證起始點可以走到所有點,所以對於每一個點,不管它選哪一個入度,都不會影響連通性

那就貪心,對於除起始點的每一個點,取它入度的最小值,然後把所有點加起來就是答案了

這玩意還比prim好寫很多

上程式碼咯

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
using namespace std;
const int INF=pow(2,31)-1;

struct star {//存邊 
    int
u,v,w; }; struct Map {// int ptn,edn; star edge[200005];//鏈式前向星儲存 int last[200005],next[200005]; void mapinit(int pig){//初始化 ptn=pig; edn=0; } void addedge(int u,int v,int w) {//加邊函式 edn++; edge[edn]=(star){u,v,w}; } void starinit() {//前向星初始化 for(int i=1;i<=ptn;i++) last[i]=-1; for(int i=1;i<=edn;i++){ int flag=edge[i].u; next[i]=last[flag]; last[flag]=i; } } }A,B;//A是縮點前的圖,B是縮點後的圖 int bel[200005];//A中點對應B中哪一個點 int Bn; int tim; int dfn[200005],low[200005]; int stack[200005],top; int isput[200005],t_vis[200005]; void tarjan(int node){//tarjan縮點 tim++; dfn[node]=tim; low[node]=tim; isput[node]=1; t_vis[node]=1; stack[top]=node; top++; for(int i=A.last[node];i!=-1;i=A.next[i]){ int to=A.edge[i].v; if(isput[to]==1){ low[node]=min(low[node],dfn[to]); }else if(t_vis[to]==1){ }else{ tarjan(to); low[node]=min(low[node],low[to]); } } if(dfn[node]==low[node]){ Bn++; for(;;){ top--; bel[stack[top]]=Bn; isput[stack[top]]=0; if(stack[top]==node||top==0) break; } } } int ans; int mn[200005]; int An,Am; int main() { for(;;){ if(scanf("%d",&An)==EOF)break; //input scanf("%d",&Am); A.mapinit(An); for(int i=1;i<=Am;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); u++;v++; A.addedge(u,v,w); } A.starinit(); //tarjan for(int i=1;i<=An;i++) {dfn[i]=0;low[i]=0;t_vis[i]=0;} tim=0; top=0; Bn=0; tarjan(1); //getB B.mapinit(Bn); for(int i=1;i<=A.edn;i++){//用A圖的強連通分量建B圖 int u=bel[A.edge[i].u],v=bel[A.edge[i].v],w=A.edge[i].w; if(u==v) continue; B.addedge(u,v,w); } B.starinit(); ans=0; //getans for(int i=1;i<=B.ptn;i++) mn[i]=INF; for(int i=1;i<=B.edn;i++){//貪心 int to=B.edge[i].v; mn[to]=min(mn[to],B.edge[i].w); } mn[bel[1]]=0;//起始點 for(int i=1;i<=B.ptn;i++){ ans+=mn[i]; } printf("%d\n",ans); } return 0; }
View Code