1. 程式人生 > >模擬考試:圖論專場

模擬考試:圖論專場

logs 無法 algorithm 線上 兩個 tdi ace include 最長

Phone

【問題描述】

由於地震使得連接汶川縣城電話線全部損壞,假如你是負責將電話線接到震中汶川縣城的負責人,汶川縣城周圍分布著N(1 <= N <= 1,000)根按1..N順次編號的廢棄的電話線桿,任意兩根電話線桿間都沒有電話線相連。一共P(1 <= P <= 10,000)對電話線桿間可以拉電話線,其余的那些由於地震使得電線桿已經倒塌而無法被連接。

i對電話線桿的兩個端點分別為Ai、Bi,它們間的距離為Li (1 <= Li <= 1,000,000)。數據中保證每對(Ai,Bi)最多只出現1次。編號為1的電話線桿已經接入了全國的電話網絡,整個縣城的電話線全都連到了編號為N的電話線桿上。也就是說,你的任務僅僅是找一條將1號和N號電話線桿連起來的路徑,其余的電話線桿並不一定要連入電話網絡。

電信公司決定支援災區免費為汶川縣城連結K(0<=K<N)對由你指定的電話線桿。對於此外的那些電話線,需要為它們付費,等於其中最長的電話線的長度(每根電話線僅連結一對電話線桿)。如果需要連結的電話線桿不超過K對,那麽總支出為0。

請你計算一下,將電話線引到震中汶川縣城最少需要在電話線上花多少錢。

Input】

輸入文件的第一行包含三個用空格隔開的整數:N,P和K

第二行到第P+1行:,每行分別都為三個用空格隔開的整數:Ai,Bi和Li

output】

輸出文件中僅包含一個整數,表示在這項工程上的最小支出。如果任務不可能完成,則輸出-1。

Sample Input】

5 7 1

1 2 5

3 1 4

2 4 8

3 2 3

5 2 9

3 4 7

4 5 6

Sample Output】

4

題解

一開始想寫分層圖,可是看到k<=1000就被嚇尿了...果斷寫了二分答案,不過據說有隊友分層圖寫AC了的...exm???總之兩種都可以寫

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<queue>
  5 #define maxn 1005
  6 #define inf 1<<29
  7 using namespace
std; 8 int n,p,k; 9 int d[maxn],vis[maxn],map[maxn][maxn],tmp[maxn][maxn]; 10 void spfa1() 11 { 12 queue<int> q; 13 for(int i=1 ; i<=n ; ++i) 14 { 15 d[i]=inf; 16 vis[i]=0; 17 } 18 vis[1]=1; 19 d[1]=0; 20 q.push(1); 21 while(!q.empty()) 22 { 23 int dd=q.front();q.pop(); 24 vis[dd]=0; 25 for(int i=1 ; i<=n ; ++i ) 26 if(map[dd][i]) 27 if(d[dd]+1<d[i]) 28 { 29 d[i]=d[dd]+1; 30 if(!vis[i]) 31 { 32 vis[i]=1; 33 q.push(i); 34 } 35 } 36 } 37 } 38 void spfa() 39 { 40 queue<int> q; 41 for(int i=1 ; i<=n ; ++i) 42 { 43 d[i]=inf; 44 vis[i]=0; 45 } 46 vis[1]=1; 47 d[1]=0; 48 q.push(1); 49 while(!q.empty()) 50 { 51 int dd=q.front();q.pop(); 52 vis[dd]=0; 53 for(int i=1 ; i<=n ; ++i ) 54 if(map[dd][i]) 55 if(d[dd]+tmp[dd][i]<d[i]) 56 { 57 d[i]=d[dd]+tmp[dd][i]; 58 if(!vis[i]) 59 { 60 vis[i]=1; 61 q.push(i); 62 } 63 } 64 } 65 } 66 int cal(int x) 67 { 68 for(int i=1 ; i<=n ; ++i) 69 for(int j=i ; j<=n ; ++j) 70 if(map[i][j]>x)tmp[i][j]=tmp[j][i]=1; 71 else tmp[i][j]=tmp[j][i]=0; 72 spfa(); 73 return d[n]; 74 } 75 int main() 76 { 77 freopen("phone.in","r",stdin); 78 freopen("phone.out","w",stdout); 79 int u,v,w; 80 scanf("%d%d%d",&n,&p,&k); 81 for(int i=1 ; i<=p ; ++i ) 82 { 83 scanf("%d%d%d",&u,&v,&w); 84 map[u][v]=map[v][u]=w; 85 } 86 spfa1(); 87 if(d[n]<=k) 88 { 89 printf("0"); 90 return 0; 91 } 92 int l=1,r=1000000; 93 while(r>l) 94 { 95 int m=(l+r)>>1; 96 if(cal(m)>k)l=m+1; 97 else r=m; 98 } 99 if(r==1000000)printf("-1"); 100 else printf("%d",r); 101 return 0; 102 }

Road(Road)

【問題描述】

N個村莊編號從1~N。小G要建一些路,使每兩個村莊都連通。連通的定義為:如果A和B直接相連,則A&B連通。如果A&C連通,B&C連通,則A&B連通。小G發現有些村莊間已經有路,小G想知道修路的最小總長度是多少。

Input】

第一行一個正整數N,表示村莊的數量。

接下來N行每行N個數,第i行第j個數表示從i到j的距離D。

接下來一個正整數M,表示已經存在的邊的數量。

接來下M行每行兩個正整數,表示已經存在的邊連接的兩個村莊的編號。

output】

一個整數,表示使所有村莊兩兩相連的最短修路距離。

Sample Input】

3

0 990 692

990 0 179

692 179 0

1

1 2

Sample Output】

179

【數據範圍】

3<=N<=100

1<=D<=1000

0<=M<=N*(N+1)/2

題解

裸的kruskal,這裏提供另外一種寫法,Floyd傳遞閉包,考試的時候寫炸了mmp,和傻逼一樣的自己...

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<queue>
 5 using namespace std;
 6 #define maxn 105
 7 int link[maxn][maxn],map[maxn][maxn];
 8 int ans,n,m,sum,cnt;
 9 void floyd()
10 {
11     for(int k=1 ; k<=n ; ++k)
12         for(int i=1 ; i<=n ; ++i)
13             if(link[i][k])
14             for(int j=i+1 ; j<=n ; ++j)
15                 if(link[k][j])link[i][j]=link[j][i]=1;
16 }
17 struct edge{
18     int u,v,w;
19 }E[maxn*maxn];
20 void add(int u,int v)
21 {
22     E[++cnt].u=u;
23     E[cnt].v=v;
24     E[cnt].w=map[u][v];
25 }
26 bool cmp(edge x,edge y){return x.w<y.w;}
27 int main()
28 {
29 //    freopen("road.in","r",stdin);
30 //    freopen("road.out","w",stdout);
31     int u,v;
32     scanf("%d",&n);
33     for(int i=1 ; i<=n ; ++i )
34         for(int j=1 ; j<=n ; ++j )
35             scanf("%d",&map[i][j]);
36     scanf("%d",&m);
37     for(int i=1 ; i<=n ; ++i)link[i][i]=1;
38     for(int i=1 ; i<=m ; ++i)
39         {
40             scanf("%d%d",&u,&v);
41             link[u][v]=link[v][u]=1;
42         }
43     floyd();
44     for(int i=1 ; i<=n ; ++i)
45         for(int j=i+1 ; j<=n ; ++j)
46             if(link[i][j]==0)add(i,j);
47     sort(E+1,E+1+cnt,cmp);
48     for(int i=1 ; i<=cnt ; ++i )
49     {
50         int u=E[i].u,v=E[i].v;
51         if(link[u][v])continue;
52         int w=E[i].w;
53         sum+=w;
54         link[u][v]=link[v][u]=1;
55         for(int k=1 ; k<=n ; ++k )
56             if(link[u][k])
57                 for(int p=1 ; p<=n ; ++p)
58                     if(link[v][p])link[k][p]=link[p][k]=1;
59     }
60     printf("%d",sum);
61     return 0;
62 }

   Sightseeing

【問題描述】

G計劃在暑假去北京旅遊。她已經知道了n個景點和景點間交通的路費,並確定好了起點和終點。為了節省路費,小G當然會選擇從起點到終點的最短路。兩條路徑上只要有一條邊不同這兩條路徑就算作不同的路徑(無重邊)。她通過觀察發現最短路的數量太少,這令她非常不爽,於是她決定比最短路長度大1的方案也可以采用。

Input】

第一行為數據組數T,T不會超過5。

第二行兩個正整數N&M,表示景點個數和邊的數量。

接下來M行,每行三個整數A,B,L,表示從A到B的路徑長為L(單向的)。

接下來一行為起點和終點。

output】

共一行,表示最短路的數量+比最短路長1的路徑數量。答案不會超過 109

Sample Input】

2

4 10

3 2 1

1 3 1

3 1 1

3 1 1

2 4 1

1 2 1

4 1 1

3 2 1

4 1 1

3 1 1

3 2

4 10

3 4 2

3 4 2

3 1 1

4 2 1

1 3 1

1 2 3

3 4 2

4 3 1

4 3 3

3 4 3

3 4

Sample Output】

5

4

【數據範圍】

2<=N<=1000

1<=M<=10000

題解

一遍spfa找最短路,然後dfs尋找路徑...

考試的時候很堅定的認為dfs過不了,10^9的數據啊...結果最大數據也只是100過一點

考試寫了兩個spfa,第二個記錄每一個點達到最短路及最短路+1情況的方案數。因為判斷+1成立的條件是dis[v]=dis[d]+w-1,因為題目寫著單向邊就很大膽的寫了,結果這尼瑪把一對雙向邊當成兩個單向邊輸入了???what the fuck??全死循環了(邊權為1的邊會造成死循環,請自行思考)沒脾氣了,暴力出奇跡,暴力出奇跡...

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<queue>
  5 #define maxn 1005
  6 #define maxm 10005
  7 #define inf 1<<29
  8 using namespace std;
  9 int n,m,st,ed,ecnt;
 10 int dis[maxn],vis[maxn],cnt[maxn][3],head[maxn],ro[maxn][maxn];
 11 struct edge{
 12     int u,v,w,next;
 13 }E[maxm];
 14 void addedge(int u,int v,int w)
 15 {
 16     E[++ecnt].u=u;
 17     E[ecnt].v=v;
 18     E[ecnt].w=w;
 19     E[ecnt].next=head[u];
 20     head[u]=ecnt;
 21 }
 22 void spfa()
 23 {
 24     queue<int> q;
 25     for(int i=1 ; i<=n ; ++i)
 26     {
 27         vis[i]=0;
 28         dis[i]=inf;
 29     }
 30     dis[st]=0;vis[st]=1;
 31     q.push(st);
 32     while(!q.empty())
 33     {
 34         int dd=q.front();q.pop();
 35         vis[dd]=0;
 36         for(int i=head[dd] ; i ; i=E[i].next )
 37         {
 38             int v=E[i].v;
 39             int w=E[i].w;
 40             if(dis[v]>=dis[dd]+w)
 41             {
 42                 dis[v]=dis[dd]+w;
 43                 if(!vis[v])
 44                 {
 45                     vis[v]=1;
 46                     q.push(v);
 47                 }
 48             }
 49         }
 50     }
 51 }
 52 int dfs(int u,int sum)
 53 {
 54     int ret(0);
 55     if(sum>dis[ed]+1)return 0;
 56     if(u==ed&&(sum==dis[ed]||sum==dis[ed]+1))return 1;
 57     for(int i=head[u] ; i ; i=E[i].next )
 58     {
 59         int v=E[i].v;
 60         int w=E[i].w;
 61         if(vis[v])continue;
 62         vis[v]=1;
 63         ret+=dfs(v,sum+w);
 64         vis[v]=0;
 65     } 
 66      return ret;
 67 }
 68 int read()
 69 {
 70     int ret(0);
 71     char ch;
 72     ch=getchar();
 73     while(ch<0||ch>9)ch=getchar();
 74     while(ch>=0&&ch<=9)
 75     {
 76         ret=ret*10+ch-0;
 77         ch=getchar();
 78     }
 79     return ret;
 80 } 
 81 void init()
 82 {
 83     for(int i=1 ; i<=n ; ++i)
 84         head[i]=0;
 85     ecnt=0;
 86 }
 87 int main()
 88 {
 89     freopen("sightseeing.in","r",stdin);
 90     freopen("sightseeing.out","w",stdout);
 91     int T,u,v,w;
 92     scanf("%d",&T);
 93     while(T--)
 94     {
 95         scanf("%d%d",&n,&m);
 96         for(int i=1 ; i<=m ; ++i )
 97         {
 98             u=read();v=read();w=read();
 99             addedge(u,v,w);
100         }
101         scanf("%d%d",&st,&ed);
102         spfa();
103         for(int i=1 ; i<=n ; ++i )vis[i]=0;
104         vis[st]=1;
105         printf("%d\n",dfs(st,0));
106         init();
107     }
108     return 0;
109 }

模擬考試:圖論專場