【TYVJ 五月图论专项有奖比赛】

最短路+TSP+最小生成树+倍增LCA+TreeDP


第一题

  其实是个TSP问题(然而我没发现),但是关键点很少,只有5个,所以用dij+heap分别预处理出来这五个点为源的最短路……

  然后枚举起点 i ,枚举这5个点的经过顺序,然后O(1)处理答案就可以了……

  容易写错的地方是 五个点的标号(a[i]),以及第几个点(i),这个地方容易搞混……

  我爆零的地方是:有个地方原来写的是 i 循环,然而我修改了以后内层变成 j 循环了,但是我没改循环内的语句……

  还有就是数组应该开 len[M<<1]的,我开成len[N<<1] 了。

 1 #include<queue>
 2 #include<vector>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<iostream>
 7 #include<algorithm>
 8 #define rep(i,n) for(int i=0;i<n;++i)
 9 #define F(i,j,n) for(int i=j;i<=n;++i)
10 #define D(i,j,n) for(int i=j;i>=n;--i)
11 using namespace std;
12 
13 int getint(){
14     int v=0,sign=1; char ch=getchar();
15     while(ch<'0'||ch>'9') {if (ch=='-') sign=-1; ch=getchar();}
16     while(ch>='0'&&ch<='9') {v=v*10+ch-'0'; ch=getchar();}
17     return v*sign;
18 }
19 typedef long long LL;
20 const int N=10010,M=50010,INF=~0u>>2;
21 /*******************template********************/
22 int to[M<<1],next[M<<1],len[M<<1],head[N],cnt;
23 void add(int x,int y,int z){
24     to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt; len[cnt]=z;
25     to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt; len[cnt]=z;
26 }
27 
28 int n,m,k;
29 int a[10],b[10],d[10][N];
30 bool vis[N],sign[N];
31 struct node{int x,d;};
32 bool operator < (node a,node b){return a.d>b.d;}
33 priority_queue<node>Q;
34 
35 void dij(int s){
36     memset(d[s],0x3f,sizeof d[s]);
37     memset(vis,0,sizeof vis);
38     d[s][a[s]]=0;
39     Q.push((node){a[s],0});
40     while(!Q.empty()){
41         int x=Q.top().x; Q.pop();
42         if (vis[x]) continue;
43         vis[x]=1;
44         for(int i=head[x];i;i=next[i])
45             if (d[s][to[i]]>d[s][x]+len[i]){
46                 d[s][to[i]]=d[s][x]+len[i];
47                 Q.push((node){to[i],d[s][to[i]]});
48             }
49     }
50 }
51 int ans=1e9+10;
52 void check(){
53     int tmp=0;
54     F(i,1,n){
55         tmp=0;
56         if (!sign[i]){
57             tmp+=d[b[1]][i]+d[b[k]][i];
58             F(j,1,k-1) tmp+=d[b[j]][ a[b[j+1]] ];
59             ans=min(ans,tmp);
60         }
61     }
62 }
63 bool chk[10];
64 void dfs(int x){
65     if (x==k+1) check();
66     F(i,1,k) if (!chk[i]){
67         b[x]=i;
68         chk[i]=1;
69         dfs(x+1);
70         b[x]=0;
71         chk[i]=0;
72     }
73 }
74 int main(){
75     n=getint(); m=getint(); k=getint();
76     F(i,1,k){
77         a[i]=getint();
78         sign[a[i]]=1;
79     }
80     F(i,1,m){
81         int x=getint(),y=getint(),z=getint();
82         add(x,y,z);
83     }
84     F(i,1,k) dij(i);
85     dfs(1);
86     printf("%d\n",ans);
87     return 0;
88 }
View Code

第二题

  跟NOIP 2012的d1t3(希望没记错时间……那题叫货车运输……)几乎完全相同的题,只不过那题是找最小,这题是最大。

  搞一个最大生成树,然后在树上倍增就可以了。

  40分?……因为忘记判impossible了……2333

 1 #include<vector>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define rep(i,n) for(int i=0;i<n;++i)
 8 #define F(i,j,n) for(int i=j;i<=n;++i)
 9 #define D(i,j,n) for(int i=j;i>=n;--i)
10 using namespace std;
11 typedef long long LL;
12 inline int getint(){
13     int r=1,v=0; char ch=getchar();
14     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
15     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
16     return r*v;
17 }
18 const int N=1e5+10,M=3e5+10;
19 /*******************template********************/
20 
21 int to[N<<1],next[N<<1],head[N],len[N<<1],cnt;
22 void add(int x,int y,int z){
23     to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt; len[cnt]=z;
24     to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt; len[cnt]=z;
25 }
26 struct edge{int u,v,w;}E[M];
27 bool cmp(const edge &a,const edge &b){return a.w<b.w;}
28 int f[N],sz[N];
29 inline int getf(int x){return f[x]==x ? x : getf(f[x]);}
30 
31 int fa[N][20],mx[N][20],dep[N],n,m;
32 void dfs(int x){
33     F(i,1,17)
34         if (dep[x]>=(1<<i)){
35             fa[x][i]=fa[fa[x][i-1]][i-1];
36             mx[x][i]=max(mx[fa[x][i-1]][i-1],mx[x][i-1]);
37         }else break;
38     for(int i=head[x];i;i=next[i])
39         if (to[i]!=fa[x][0]){
40             fa[to[i]][0]=x;
41             dep[to[i]]=dep[x]+1;
42             mx[to[i]][0]=len[i];
43             dfs(to[i]);
44         }
45 }
46 int query(int x,int y){
47     if (dep[x]<dep[y]) swap(x,y);
48     int t=dep[x]-dep[y];
49     int ans=0;
50     F(i,0,17) if (t&(1<<i)){
51         ans=max(mx[x][i],ans);
52         x=fa[x][i];
53     }
54     D(i,17,0) if (fa[x][i]!=fa[y][i]){
55         ans=max(mx[x][i],ans);
56         ans=max(mx[y][i],ans);
57         x=fa[x][i]; y=fa[y][i];
58     }
59     if (x!=y) ans=max(ans,max(mx[x][0],mx[y][0]));
60     return ans;
61 }
62 int main(){
63     n=getint(); m=getint();
64     F(i,1,m){
65         int x=getint(),y=getint(),z=getint();
66         E[i]=(edge){x,y,z};
67     }
68     sort(E+1,E+m+1,cmp);
69     F(i,1,n) f[i]=i,sz[i]=1;
70     F(i,1,m){
71         int f1=getf(E[i].u),f2=getf(E[i].v);
72         if (f1!=f2){
73             if (sz[f1]>sz[f2]) swap(f1,f2);
74             f[f1]=f2;
75             sz[f2]+=sz[f1];
76             add(E[i].u,E[i].v,E[i].w);
77         }
78     }
79     
80     dfs(1);
81     int T=getint();
82     while(T--){
83         int x=getint(),y=getint();
84         if (getf(x)!=getf(y)) puts("impossible");
85         else printf("%d\n",query(x,y));
86     }
87     return 0;
88 }
View Code

第三题

  我并不会写……只好预处理出来dist[i][j]数组,然后$N^2$枚举+O(n)判断……三次方的做法骗了30分= =

  然而正解是找树的重心?预处理出来每棵子树的答案,由于整棵树分成的两部分是一棵完整的子树+剩下的部分,所以枚举那个砍掉的子树?在再加上一些神奇的技巧……

  然而一上午也没yy出来果然代码能力就是渣渣,sad……

  UPD:2015年5月20日 16:28:33

  Orz zyf神犇

  果然是……枚举断了哪条边,然后暴力修改= =用dfs整棵树来选边就可以,从当前点沿fa修改上去,两半树各求一遍答案……ok……无限ym啊……

 1 //TYVJ C
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define rep(i,n) for(int i=0;i<n;++i)
 8 #define F(i,j,n) for(int i=j;i<=n;++i)
 9 #define D(i,j,n) for(int i=j;i>=n;--i)
10 #define pb push_back
11 using namespace std;
12 typedef long long LL;
13 inline int getint(){
14     int r=1,v=0; char ch=getchar();
15     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
16     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
17     return r*v;
18 }
19 const int N=100010;
20 /*******************template********************/
21 int to[N<<1],next[N<<1],head[N],cnt;
22 void add(int x,int y){
23     to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt;
24     to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt;
25 }
26 
27 int n,a[N],f[N][2],dep[N],s[N],fa[N],cut;
28 LL g[N],ans=1e15;
29 void dfs(int x){
30     for(int i=head[x];i;i=next[i])
31         if (to[i]!=fa[x]){
32             dep[to[i]]=dep[x]+1;
33             fa[to[i]]=x;
34             dfs(to[i]);
35             s[x]+=s[to[i]];
36             if (s[to[i]]>s[f[x][0]]) f[x][1]=f[x][0],f[x][0]=to[i];
37             else if (s[to[i]]>s[f[x][1]]) f[x][1]=to[i];
38             g[x]+=g[to[i]]+s[to[i]];
39         }
40 }
41 LL getans(int x,int cnt){
42     int t=(f[x][0]==cut || s[f[x][1]]>s[f[x][0]]) ? f[x][1] : f[x][0];
43     if (2*s[t]>cnt) return 2*s[t]-cnt+getans(t,cnt);
44     else return 0;
45 }
46 void dp(int x){
47     for(int i=head[x];i;i=next[i])
48         if (to[i]!=fa[x]){
49             cut=to[i];
50             for(int j=x;j;j=fa[j]) s[j]-=s[to[i]];
51             ans=min(ans,g[1]-g[to[i]]-(LL)s[to[i]]*dep[to[i]]-getans(1,s[1])+g[to[i]]-getans(to[i],s[to[i]]));
52             for(int j=x;j;j=fa[j]) s[j]+=s[to[i]];
53             dp(to[i]);
54         }
55 }
56 
57 int main(){
58 #ifndef ONLINE_JUDGE
59     freopen("C.in","r",stdin);
60     freopen("C.out","w",stdout);
61 #endif
62     n=getint();
63     F(i,2,n){
64         int x=getint(),y=getint();
65         add(x,y);
66     }
67     F(i,1,n) s[i]=getint();
68     dfs(1);
69     dp(1);
70     printf("%lld\n",ans);
71     return 0;
72 }
View Code

 

posted @ 2015-05-18 11:04  Tunix  阅读(214)  评论(0编辑  收藏  举报