poj3764解题报告
来源:互联网 发布:android6.0 相机源码 编辑:程序博客网 时间:2024/06/11 20:11
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">这是第一次写博客发解题报告,当然我目前也还是个大水逼,所以代码写的也不太好,见谅。</span>
这道题就是要求在树中找两个结点,且两个结点之间路径唯一,求最长的异或路径。很明显不能用暴力,O(N2)时间复杂度100000个点。首先我们需要知道一个性质:a^b = (a^c)^(b^c),这样就可以考虑找出a与b公共的c,实际上就是求出从根节点到每个节点的异或值,这样任意两个点做异或,即是他们之间的异或路径(相同部分异或抵消了)。先遍历DFS遍历一遍,找出所有结点到树根的路径异或值,则问题就转化成了求这些点中任意两个点的异或值,接下来就很简单了,将DFS所得的每个点的异或值转化成二进制数存进字典树,然后从高位至低位对字典树进行贪心,找出最大的那个值。字典树的时间复杂度为O(31*n),dfs时间复杂度为O(n)。
这道题字典树最多有3100000个点,所以容易TLE,一定要进行剪枝,推荐使用静态数组存字典树,但我是用的动态开辟数组存树,所以过的十分勉强。
另外这题也让我长了点姿势,位运算1<<31会溢出,楼主确实还很水,因为这个WA了两次。。。
/**memory 27468KB time 1282ms */#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int maxn=100010;int cnt,sum,flag;int dis[maxn],head[maxn],s[maxn][33];struct edge{ int v,w; int next;}edge[2*maxn];struct node{ node *a[2]; int p;};void addedge(int u,int v,int w){ edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].w=w; edge[cnt].next=head[v]; head[v]=cnt++;}void dfs(int u,int fa){ for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==fa) continue; dis[v]=dis[u]^edge[i].w; dfs(v,u); }}void insert(int k,int m,node *h){ h->p++; if(k>30) return; if(h->a[s[m][k]]!=NULL) insert(k+1,m,h->a[s[m][k]]); else{ for(int i=k;i<=30;i++){ node*t=new node; t->p=1; for(int j=0;j<2;j++) t->a[j]=NULL; h->a[s[m][i]]=t; h=t; } }}void find(int k,int m,node*h){ if(h->a[!s[m][k]]!=NULL){ sum+=(1<<(30-k)); find(k+1,m,h->a[!s[m][k]]); } else if(h->a[s[m][k]]!=NULL) find(k+1,m,h->a[s[m][k]]); else return;}int main(){ //freopen("xor.txt","r",stdin); int u,v,w,n; while(~scanf("%d",&n)){ node *h=new node; h->p=0; for(int i=0;i<2;i++) h->a[i]=NULL; cnt=0; memset(head,-1,sizeof(head)); for(int i=1;i<n;i++){ scanf("%d %d %d",&u,&v,&w); addedge(u,v,w); } dis[0]=0; dfs(0,-1); int maxdis=0; for(int i=0;i<n;i++) maxdis=max(maxdis,dis[i]); for(flag=0;flag<31;flag++) if(maxdis<(1<<flag)) break; int ans=0; for(int i=0;i<n;i++){ int dist=dis[i]; for(int j=30;j>=0;j--){ s[i][j]=dist%2; dist=dist>>1; } insert(0,i,h); //注意这里是每insert一次,就find一次,不要把insert和find放到两个循环里,避免重复贪心。 sum=0; find(0,i,h); ans=max(ans,sum); if(ans==(1<<flag)-1) //flag是一个剪枝,如果去掉就会TLE break; } printf("%d\n",ans); }}
0 0
- poj3764解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- Antiprime解题报告
- expr解题报告
- 华容道解题报告
- tju解题报告
- zju1062/pku1095解题报告
- UsacoGate解题报告 --- 序曲
- ZJU 2060 解题报告
- ZJU 1331 解题报告
- ZJU 1115 解题报告
- ZJU1057解题报告
- C#Winform实现类似Android的Listener
- 数据库内连接与外连接
- HTML 5 Canvas vs. SVG
- UIActionSheet 按钮不响应点击事件的解决方法
- 小递归
- poj3764解题报告
- Async详解之一:流程控制
- android 开发需要的工具
- win7,远程桌面连接如何调用 C2050 卡
- Objective-C十六进制字符串转为十进制
- 安卓用SharedPreferences保存对象到本地和取出方法
- 关于打开VC6.0开发文件出错文件问题
- WindowMediaPlayer获取视频长度
- log4net使用详解