1. 程式人生 > >西電10.9校內賽補題

西電10.9校內賽補題

sed continue ssi 最短 emp alt while pos src

D.UVa12880

解題關鍵:dfs,判斷每個人是否願意被其他人交換,註意保證每個人只能被交換一次。

技術分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<iostream>
 7 #define maxn 220000
 8 using namespace std;
 9 typedef long long ll;
10 struct Edge{ 11 int nxt; 12 int to; 13 }e[maxn]; 14 int head[maxn],cnt,pre[maxn]; 15 bool vis[maxn]; 16 void add_edge(int u,int v){//單向 17 e[cnt].to=v; 18 e[cnt].nxt=head[u]; 19 head[u]=cnt++; 20 } 21 bool dfs(int u){ 22 for(int i=head[u];i!=-1;i=e[i].nxt){ 23 int
v=e[i].to; 24 if(vis[v]) continue; 25 vis[v]=true; 26 if(pre[v]==-1||dfs(pre[v])){ 27 pre[v]=u; 28 return true; 29 } 30 } 31 return false; 32 } 33 int main(){ 34 int n,m,a,b; 35 while(scanf("%d%d",&n,&m)!=EOF){
36 memset(head, -1, sizeof head); 37 memset(pre,-1,sizeof pre); 38 cnt=0; 39 for(int i=0;i<m;i++){ 40 scanf("%d%d",&a,&b); 41 add_edge(a,b); 42 } 43 for(int i=0;i<n;i++){ 44 memset(vis,0,sizeof vis); 45 dfs(i); 46 } 47 bool flag=false; 48 for(int i=0;i<n;i++){ 49 if(pre[i]==-1){ 50 flag=true; 51 break; 52 } 53 } 54 if(flag) printf("NO\n"); 55 else printf("YES\n"); 56 } 57 return 0; 58 }
View Code

E.hdu4313

解題關鍵:正向的思路是將邊從小到大排序,如果去掉某條邊,兩個特殊點並起來了,則需去掉該邊,我們反向考慮,將邊從大到小排序,依次向圖中加邊,如果兩個點並起來了,則需去掉該邊。

技術分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<vector>
 7 #include<cmath>
 8 #define maxn 100020
 9 using namespace std;
10 typedef long long ll;
11 int par[maxn],n,k;
12 //bool vis[maxn];
13 struct edge{
14     int u;
15     int v;
16     int w;
17 }e[maxn];
18 bool flag[maxn];
19 bool cmp(const edge &a,const edge &b){
20     return a.w>b.w;
21 }
22 void init1(){
23     for(int i=0;i<=n;i++) par[i]=i;
24 }
25 
26 int find1(int x){
27     if(par[x]==x) return x;
28     else return par[x]=find1(par[x]);
29 }
30 
31 void unite(int x,int y){
32     par[x]=y;
33 }
34 
35 int main(){
36     int t,a;
37     ios::sync_with_stdio(0);
38     cin>>t;
39     while(t--){
40         memset(flag, 0, sizeof flag);
41         cin>>n>>k;
42         init1();
43         for(int i=0;i<n-1;i++){
44             cin>>e[i].u>>e[i].v>>e[i].w;
45         }
46         sort(e,e+n-1,cmp);
47         for(int i=0;i<k;i++){
48             cin>>a;
49             flag[a]=1;
50         }
51         ll ans=0;
52         for(int i=0;i<n-1;i++){
53             if(flag[find1(e[i].u)]&&flag[find1(e[i].v)]){
54                 ans+=e[i].w;
55             }
56             else if(flag[find1(e[i].u)]){
57                 unite(find1(e[i].v),find1(e[i].u));
58             }else{
59                 unite(find1(e[i].u), find1(e[i].v));
60             }
61         }
62         cout<<ans<<"\n";
63     }
64     return 0;
65 }
View Code

G.hdu4318

解題關鍵:最短路轉化為最長路。

技術分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<cmath>
 7 #include<queue>
 8 using namespace std;
 9 const int maxn=50002;
10 const int maxm=2600010;
11 int head[maxn],tot,n,m;
12 struct edge{
13     int to;
14     double w;
15     int nxt;
16 }e[maxm];
17 void add_edge(int u,int v,double w){
18     e[tot].w=w;
19     e[tot].to=v;
20     e[tot].nxt=head[u];
21     head[u]=tot++;
22 }
23 bool vis[maxn];
24 queue<int>que;//隊列是點的隊列
25 double d[maxn];
26 void spfa(int s){
27     for(int i=0;i<=n;i++) d[i]=0.0;
28     memset(vis,0,sizeof vis);
29     while (!que.empty()) que.pop();
30     que.push(s);
31     vis[s]=true;
32     d[s]=1.0;
33     while (!que.empty()){
34         int u=que.front();
35         que.pop();
36         vis[u]=false;
37         for (int i=head[u];i!=-1;i=e[i].nxt){
38             int v=e[i].to;
39             double w=e[i].w;
40             if (d[v]<d[u]*w){
41                 d[v]=d[u]*w;
42                 if (!vis[v]){
43                     vis[v]=true;
44                     que.push(v);//hash一下,可判斷是否存在負環
45                 }
46             }
47         }
48     }
49 }
50 int main(){
51     int a,b,k,td;
52     //double c;
53     while(scanf("%d",&n)!=EOF){
54         memset(head, -1, sizeof head);
55         tot=0;
56         for(int i=0;i<n;i++){
57             scanf("%d",&k);
58             for(int j=0;j<k;j++){
59                 scanf("%d%d",&b,&td);
60                 add_edge(i+1,b,1-td*0.01);
61             }
62         }
63         scanf("%d%d%d",&a,&b,&td);
64         spfa(a);
65         if(d[b]==0){
66             printf("IMPOSSIBLE!\n");
67         }else{
68             printf("%.2f\n",td-td*d[b]);
69         }
70     }
71     return 0;
72 }
View Code

西電10.9校內賽補題