[CEOI1997]参观洞穴 解题报告
来源:互联网 发布:制作淘宝店铺标志 编辑:程序博客网 时间:2024/05/24 16:16
这道题挺有意思的,难点主要在建模。
“对于每个房间来说,我们都能找到一条通往任意一个其他房间的只经过内通道的路线,但是如果我们规定每个内通道只能走一次的话,这样的路线是惟一的。”
也就是说,在删掉外通道以后,所有节点形成了一棵树。
但是我比较傻逼。。我只想到了内节点形成了一棵树(而且是二叉树,但是我不知道这有什么用),所以我以为就是用k条带权树上路径去不重不漏地覆盖整棵树,于是就写了一个O(n^2)的DP。。(结果不知道为什么在POJ上跑的比我O(N)的标算还快)
“从每个房间出发,恰好有三条通道通往另外三个不同的房间。显然,从每个外房间出发的三条通道分别通往它在圆圈上两个相邻的外房间和某个内房间。”
首先,可以发现,如果忽略1号节点,并以与1号节点相邻的内节点(它是一定存在且唯一的)为根的话,所形成的树的所有叶节点都是外节点,所有外节点也都是叶节点。
而且这还是一棵二叉树。
“所有的房间和通道在同一层且任意两条通道不交叉。”这句话的意思是外房间在环上是依据某种DFS序排列的,而且哈密顿序中环上节点的出现序列必然是沿环的。
由于一号节点比较特殊,所以我们考虑枚举一号节点的进出方式之后,将会剩下一坨二叉树。那么我们考虑每个树的根,实际上如果它要被选择的话,它只能被从左子树最右边的孙子和右子树最左边的孙子之间的路径取到——因为这是一棵二叉树。所以路径的选择竟然是唯一的!
所以我们可以先构出二叉树,然后把所有点按dfs序排序,然后处理的时候按dfs序对没被标记的点依次处理。然后还有各种蛋疼的细节,写了我一上午。
Code(O(N!)DFS):
#include<cstdio>#include<cstring>int tmp[505];int ptr[505],next[1505],w[1505],succ[1505],etot=1;void addedge(int u,int v,int wt){ next[etot]=ptr[u],ptr[u]=etot,succ[etot]=v,w[etot++]=wt;}bool p[505];int ans=0x7fffffff,n,ansp[505];void dfs(int node,int nown,int noww,int top){ if(noww>=ans)return; p[node]=1,tmp[top]=node; for(int i=ptr[node];i;i=next[i]) if(!p[succ[i]])dfs(succ[i],nown+1,noww+w[i],top+1); else if(succ[i]==1&&nown==n-1){ ans=noww+w[i]; memcpy(ansp,tmp,sizeof(int)*n); } p[node]=0;}int main(){ freopen("cave.in","r",stdin); freopen("cave.out","w",stdout); int m,k; scanf("%d%d",&n,&k); m=n+(n>>1); int i,u,v,wt; for(i=m;i--;){ scanf("%d%d%d",&u,&v,&wt); addedge(u,v,wt),addedge(v,u,wt); } dfs(1,0,0,0); putchar('1'); for(i=1;i<n;++i)printf(" %d",ansp[i]);}
Code(O(N^2)DP):
#include<cstdio>#include<cstring>#include<cmath>#include<iostream>using namespace std;#include<algorithm>int next[1505],succ[1505],ptr[505],w[1505],etot=1;inline void addedge(int u,int v,int wt){ next[etot]=ptr[u],ptr[u]=etot,w[etot]=wt,succ[etot++]=v;}inline void in(int &x){ char c=getchar(); while(c<'0'||c>'9')c=getchar(); x=0; for(;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');}int depth[505],k;inline void depdfs(int node,int ftr){ depth[node]=depth[ftr]+1; for(int i=ptr[node];i;i=next[i]) if(succ[i]!=ftr&&succ[i]>k) depdfs(succ[i],node);}int road[505][505],cost[505],nnode;inline bool finddfs(int node,int x,int ftr){ road[node][++road[node][0]]=x; for(int i=ptr[x];i;i=next[i]) if(succ[i]!=ftr){ cost[node]+=w[i]; //cout<<"Get:"<<succ[i]<<"("<<w[i]<<")\n"; if(succ[i]==nnode)return 1; else if(succ[i]>k&&finddfs(node,succ[i],x))return 1; cost[node]-=w[i]; //cout<<"Del:"<<succ[i]<<"(-"<<w[i]<<")\n"; } --road[node][0]; return 0;}bool p[505];//这个点在不在当前所选的路径上。 bool flag[505];//外边界的点进不进去。 int f[505],chosen[505];#include<vector>vector<int> belong[505];#define inf 1000000000inline int dfs(int node,int ftr){ if(!p[node])return f[node]; int ans=0; for(int i=ptr[node];i;i=next[i]) if(succ[i]!=ftr&&succ[i]>k) ans+=dfs(succ[i],node); return ans;}inline void dpdfs(int node,int ftr){ for(int i=ptr[node];i;i=next[i]) if(succ[i]!=ftr&&succ[i]>k) dpdfs(succ[i],node); for(int i,j=belong[node].size();j--;){ for(i=road[belong[node][j]][0];i;--i)p[road[belong[node][j]][i]]=1; int tmp=cost[belong[node][j]]; for(i=ptr[node];i;i=next[i]) if(succ[i]!=ftr&&succ[i]>k) tmp=min(tmp+dfs(succ[i],node),inf); if(tmp<f[node]){ f[node]=tmp; chosen[node]=belong[node][j]; //cout<<node<<":"<<chosen[node]<<"->"<<f[node]<<endl; } for(i=road[belong[node][j]][0];i;--i)p[road[belong[node][j]][i]]=0; }}inline void outdfs(int node,int ftr){ if(!p[node]){ flag[chosen[node]]=1; for(int i=road[chosen[node]][0];i;--i)p[road[chosen[node]][i]]=1; } for(int i=ptr[node];i;i=next[i]) if(succ[i]!=ftr&&succ[i]>k) outdfs(succ[i],node);}int main(){ freopen("cave.in","r",stdin); //freopen("cave_TA.out","w",stdout); int n,m; in(n),in(k); m=3*n>>1; int i,j,u,v,wt; for(i=m;i--;){ in(u),in(v),in(wt); addedge(u,v,wt),addedge(v,u,wt); } depdfs(k+1,0); int node=1,highest; int sum=0,tmp; for(i=ptr[1];i;i=next[i]) if(succ[i]<=k){ nnode=succ[i]; cost[node]=-w[i]; sum+=w[i]; break; } do{ //cout<<"------"<<node<<"----\n"; for(i=ptr[node];i;i=next[i]) if(succ[i]>k){ cost[node]+=w[i]; finddfs(node,succ[i],0); highest=succ[i]; for(j=road[node][0];j;--j) if(depth[road[node][j]]<depth[highest]) highest=road[node][j]; belong[highest].push_back(node); break; } for(i=ptr[nnode];i;i=next[i]){ if(succ[i]!=node&&succ[i]<=k){ node=nnode; nnode=succ[i]; if(node!=1){ cost[node]=-w[i]; sum+=w[i]; } break; } } }while(node!=1); memset(f,60,sizeof(f)); /*for(i=1;i<=k;++i){ cout<<i<<":"; for(j=1;j<=road[i][0];++j)cout<<road[i][j]<<" "; cout<<":"<<cost[i]<<endl; } for(i=k+1;i<=n;++i){ cout<<i<<":"; for(j=belong[i].size();j--;)printf("%d ",belong[i][j]); puts(""); } cout<<"------------------\n";*/ dpdfs(k+1,0); outdfs(k+1,0); //cout<<sum<<"->"<<sum+f[k+1]<<endl; for(i=ptr[1];i;i=next[i]) if(succ[i]<=k){ nnode=succ[i]; break; } putchar('1'); do{ if(flag[node]) for(i=1;i<=road[node][0];++i) printf(" %d",road[node][i]); for(i=ptr[nnode];i;i=next[i]) if(succ[i]!=node&&succ[i]<=k){ node=nnode; nnode=succ[i]; break; } if(node!=1)printf(" %d",node); }while(node!=1); //cout<<":"<<sum+f[k+1]<<endl;}
Code(O(N)):
#include<cstdio>#include<cstring>#include<cmath>#include<cstring>#include<iostream>using namespace std;#include<algorithm>int n,k;int ls[505],ldis[505],rs[505],rdis[505],crate[505];int cnext[505],cdis[505];//圆上下一点。 int next[1505],succ[1505],w[1505],ptr[505],etot=1;int sorted[505],stot=1;inline void addedge(int u,int v,int wt){ next[etot]=ptr[u],ptr[u]=etot,w[etot]=wt,succ[etot++]=v;}inline void build(int node,int ftr){ if(node>k){ for(int i=ptr[node];i;i=next[i]) if(succ[i]!=ftr){ build(succ[i],node); if(ls[node]){ rs[node]=succ[i]; rdis[node]=w[i]; } else{ ls[node]=succ[i]; ldis[node]=w[i]; } } if(crate[rs[node]]<crate[ls[node]]){ swap(ls[node],rs[node]); swap(ldis[node],rdis[node]); } crate[node]=crate[ls[node]]; }}inline void dfs(int node){ sorted[stot++]=node; if(node>k)dfs(ls[node]),dfs(rs[node]);}bool used[505];int now,ans=0x7fffffff,road[505],ansroad[505],ansflag;inline void work(int flag){ for(int i=1,j;i<n;++i){ if(!used[sorted[i]]) if(sorted[i]>k){ now+=ldis[sorted[i]]+rdis[sorted[i]]; for(j=ls[sorted[i]];j>k;j=rs[j]){ now+=rdis[j]; //cout<<j<<" "; used[j]=1; } //cout<<j<<" "; used[j]=1; road[j]=sorted[i]; //cout<<"("<<sorted[i]<<":<-"<<j<<")"; for(j=rs[sorted[i]];j>k;j=ls[j]){ now+=ldis[j]; //cout<<j<<" "; used[j]=1; } //cout<<j<<"\n"; } else{ //cout<<sorted[i]<<" chooses go out.\n"; road[sorted[i]]=sorted[i]; now+=cdis[sorted[i]]; } } if(ans>now){ //cout<<"Get:"<<flag<<endl; ans=now,ansflag=flag; memcpy(ansroad,road,sizeof(road)); }}inline void rout(int node){ if(node>k){ rout(rs[node]); printf(" %d",node); }}int main(){ freopen("cave.in","r",stdin); freopen("cave.out","w",stdout); scanf("%d%d",&n,&k); int m=(n>>1)+n; int u,v,wt; while(m--){ scanf("%d%d%d",&u,&v,&wt); addedge(u,v,wt),addedge(v,u,wt); } int node=1,nnode,ctot=0,i; crate[node]=ctot++; for(i=ptr[node];i;i=next[i]) if(succ[i]<=k){ nnode=succ[i]; cdis[1]=w[i]; break; } cnext[1]=nnode; while(nnode!=1) for(i=ptr[nnode];i;i=next[i]) if(succ[i]<=k&&succ[i]!=node){ cnext[nnode]=succ[i]; crate[node=nnode]=ctot++; cdis[node]=w[i]; nnode=succ[i]; break; } int outnode,outw; for(i=ptr[1];i;i=next[i]) if(succ[i]>k){ outnode=succ[i]; outw=w[i]; build(succ[i],1); dfs(succ[i]); break; } //外到1,1到外。 //puts("-----1-------"); memset(used,0,sizeof(used)); now=cdis[sorted[n-1]]+cdis[1]; used[1]=used[sorted[n-1]]=1; work(1); //内到1,1到外。 //puts("------2------"); memset(used,0,sizeof(used)); now=cdis[1]+outw; used[sorted[n-1]]=used[1]=1; for(i=outnode;i>k;i=rs[i]){ now+=rdis[i]; used[i]=1; } work(2); //外到1,1到内。 //puts("-----3-----"); memset(used,0,sizeof(used)); now=cdis[sorted[n-1]]+outw; used[1]=used[sorted[n-1]]=1; for(i=outnode;i>k;i=ls[i]){ now+=ldis[i]; used[i]=1; } work(3); putchar('1'); if(ansflag==3) for(i=outnode;i>k;i=ls[i]) printf(" %d",i); for(node=cnext[1];node!=sorted[n-1];node=cnext[node]){ printf(" %d",node); if(ansroad[node]!=node){ //cout<<"("<<ansroad[node]<<":"<<ls[ansroad[node]]<<","<<rs[ansroad[node]]<<")"; rout(ls[ansroad[node]]); printf(" %d",ansroad[node]); for(i=rs[ansroad[node]];i>k;i=ls[i])printf(" %d",i); } } printf(" %d",node); if(ansflag==2)rout(outnode); //cout<<":"<<ans<<endl;}
- [CEOI1997]参观洞穴 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- Antiprime解题报告
- expr解题报告
- 华容道解题报告
- tju解题报告
- zju1062/pku1095解题报告
- UsacoGate解题报告 --- 序曲
- ZJU 2060 解题报告
- ZJU 1331 解题报告
- ZJU 1115 解题报告
- ZJU1057解题报告
- centos 6.5 安装mongodb2.6
- nim语言
- CLLocationManager位置服务对象和地图的简单结合使用
- STRTOK函数的用法
- Codeforces Round #310 (Div. 1)B,C,D(set+线段树)
- [CEOI1997]参观洞穴 解题报告
- 序列化和反序列化
- mako模板调试与使用技巧
- Mysql主从复制原理
- Scramble String
- Nagel算法
- HDU 3395 Special Fish(最大费用流)
- Leetcode:Palindrome Number
- poj 1837