匹配 解题报告
来源:互联网 发布:拍摄淘宝服装图片技巧 编辑:程序博客网 时间:2024/06/01 03:58
求一棵树的最大匹配以及最大匹配方案数模m。
时间限制:2s
空间限制:32MB
= =这是一道卡内存傻题,一个显然的DP方程是设f(n,0/1)为这个点向其父亲的边选或不选这个子树能得到的最大匹配,然后g(n,0/1)是其方案数,然后随便转移一下就好了。
注意到状态有4*n个,而内存太小了,最多只能开5*n的数组。。我感觉遍历一棵树似乎至少就需要3*n,所以说DP的状态必须要动态地记录。
然后我使用的沙茶方法是一种关于直径的分治,就是每次选出一条直径,然后从下向上DP,不在直径上的就递归处理,这样每一层的空间复杂度都是O(1)。显然,每一层的直径都是严格小于上一层的,直径长度大于
但是蛋疼的地方就是初始化的时候我默认把叶子节点的g初始化为1,然后对于n=1,m=1的时候跪了。这已经是我第二次因为模的数等于1跪掉了,所以说对于m有范围的情况一定要试m=1的情况!
然而我考完以后才发现这其实只要按链剖一样按size找就可以轻易地把空间复杂度降到
代码(
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<bitset>using namespace std;bitset<1500005> flag;int succ[3000005],ptr[1500005],next[3000005],etot=1;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');}void addedge(int u,int v){ next[etot]=ptr[u],ptr[u]=etot,succ[etot++]=v;}int m,n;//next[1..n]表示i的儿子们在哪里开始的,succ[1..n]存它的儿子们,ptr[1..n]存它的父亲们。 //next[n+1+1..n+1+n]表示其儿子们的最大深度,succ[n+1..n+n]存每个点的depth struct DS{ int f[2],g[2];};typedef long long LL;#define inf 1000000000DS dfs(int node,int depth){ int i,Maxson; while(next[node]!=next[node+1]){ succ[n+node]=depth; Maxson=succ[next[node]]; for(i=next[node];++i<next[node+1];) if(next[n+1+succ[i]]>next[n+1+Maxson]) Maxson=succ[i]; node=Maxson; } succ[n+node]=depth; DS ans,sps,Max,now; for(;;){ ans=(DS){{0,1},{1%m,1%m}},Max=(DS){{inf,-inf},{1%m,1%m}}; for(i=next[node];i<next[node+1];++i){ if(succ[n+succ[i]])now=sps; else now=dfs(succ[i],depth+1); if(now.f[1]-now.f[0]>Max.f[1]-Max.f[0]){ Max=now; Max.g[0]=(LL)ans.g[1]*now.g[1]%m; if(now.f[1]-now.f[0]==0)Max.g[0]=(Max.g[0]+(LL)ans.g[1]*now.g[0])%m; } else if(now.f[1]-now.f[0]==Max.f[1]-Max.f[0])Max.g[0]=((LL)Max.g[0]*now.g[0]+(LL)ans.g[1]*now.g[1])%m; else Max.g[0]=(LL)Max.g[0]*now.g[0]%m; ans.f[1]+=now.f[0]; ans.g[1]=(LL)ans.g[1]*now.g[0]%m; } if(Max.f[1]-Max.f[0]>=0){ ans.g[0]=Max.g[0]; ans.f[0]=ans.f[1]-1+Max.f[1]-Max.f[0]; } else{ ans.g[0]=ans.g[1]; ans.f[0]=ans.f[1]-1; } sps=ans; //cout<<node<<":"<<ans.f[0]<<","<<ans.f[1]<<" "<<ans.g[0]<<","<<ans.g[1]<<endl; if(succ[n+ptr[node]]==succ[n+node])node=ptr[node]; else return ans; }}int main(){ freopen("match.in","r",stdin); freopen("match.out","w",stdout); int i,u,v,j; in(n); for(i=n;--i;){ in(u),in(v); addedge(u,v),addedge(v,u); } in(m); //dfs出父亲来。 int node=1,tmp; flag[1]=1; while(node){ if(!flag[succ[ptr[node]]]){ flag[succ[ptr[node]]]=1; tmp=node; node=succ[ptr[node]]; ptr[tmp]=next[ptr[tmp]]; } else if(next[ptr[node]])swap(succ[ptr[node]],succ[next[ptr[node]]]); else{ ptr[node]=succ[ptr[node]]; node=ptr[node]; } } //按父亲排序 //next[n+2..n+n]作为新next,succ[n+1..n]作为新的表头。 //ptr[1..n]是父亲,next[1..n]作为分界点。 memset(succ,0,sizeof(succ)); memset(next,0,sizeof(next)); for(i=1;i<=n;++i)next[i+n]=succ[n+ptr[i]],succ[n+ptr[i]]=n+i; next[1]=1; for(i=1;i<=n;++i){ next[i+1]=next[i]; for(j=succ[n+i];j;j=next[j])succ[next[i+1]++]=j-n; } for(i=1;i<=n;++i)next[n+2+i]=0; //求最大深度 flag.reset(); for(i=n;i;--i)succ[n+i]=next[i]; node=1; while(node){ if(succ[n+node]==next[node+1]){ ++next[n+1+node]; flag[node]=1; node=ptr[node]; } else if(!flag[succ[succ[n+node]]])node=succ[succ[n+node]]; else next[n+1+node]=max(next[n+1+node],next[n+1+succ[succ[n+node]++]]); } for(i=n;i;--i)succ[n+i]=0; //dp DS ans=dfs(1,1); printf("%d\n%d\n",ans.f[0],ans.g[0]);}
代码(链剖):
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<ctime>#include<iostream>#include<bitset>using namespace std;bool flag[1500005];int succ[3000005],ptr[1500005],next[3000005],etot=1;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');}void addedge(int u,int v){ next[etot]=ptr[u],ptr[u]=etot,succ[etot++]=v;}int m,n;//next[1..n]表示i的儿子们在哪里开始的,succ[1..n]存它的儿子们,ptr[1..n]存它的父亲们。 //next[n+1+1..n+1+n]表示其儿子们的最大深度,succ[n+1..n+n]存每个点的depth struct DS{ int f[2]; long long g[2];};#define inf 1000000000DS dfs(int node,int depth){ int i,Maxson; while(next[node]!=next[node+1]){ succ[n+node]=depth; Maxson=succ[next[node]]; for(i=next[node];++i<next[node+1];) if(next[n+1+succ[i]]>next[n+1+Maxson]) Maxson=succ[i]; node=Maxson; } succ[n+node]=depth; DS ans,sps,Max,now; for(;;){ ans=(DS){{0,1},{1%m,1%m}},Max=(DS){{inf,-inf},{1%m,1%m}}; for(i=next[node];i<next[node+1];++i){ if(succ[n+succ[i]])now=sps; else now=dfs(succ[i],depth+1); if(now.f[1]-now.f[0]>Max.f[1]-Max.f[0]){ Max=now; Max.g[0]=ans.g[1]*now.g[1]%m; if(now.f[1]-now.f[0]==0)Max.g[0]=(Max.g[0]+ans.g[1]*now.g[0])%m; } else if(now.f[1]-now.f[0]==Max.f[1]-Max.f[0])Max.g[0]=(Max.g[0]*now.g[0]+ans.g[1]*now.g[1])%m; else Max.g[0]=Max.g[0]*now.g[0]%m; ans.f[1]+=now.f[0]; ans.g[1]=ans.g[1]*now.g[0]%m; } if(Max.f[1]-Max.f[0]>=0){ ans.g[0]=Max.g[0]; ans.f[0]=ans.f[1]-1+Max.f[1]-Max.f[0]; } else{ ans.g[0]=ans.g[1]; ans.f[0]=ans.f[1]-1; } sps=ans; //cout<<node<<":"<<ans.f[0]<<","<<ans.f[1]<<" "<<ans.g[0]<<","<<ans.g[1]<<endl; if(succ[n+ptr[node]]==succ[n+node])node=ptr[node]; else return ans; }}int main(){ freopen("match.in","r",stdin); freopen("match.out","w",stdout); int i,u,v,j; in(n); for(i=n;--i;){ in(u),in(v); addedge(u,v),addedge(v,u); } in(m); //dfs出父亲来。 int node=1,tmp; flag[1]=1; //printf("%f\n",(double)clock()/CLOCKS_PER_SEC); while(node){ if(!flag[succ[ptr[node]]]){ flag[succ[ptr[node]]]=1; tmp=node; node=succ[ptr[node]]; ptr[tmp]=next[ptr[tmp]]; } else if(next[ptr[node]])swap(succ[ptr[node]],succ[next[ptr[node]]]); else{ ptr[node]=succ[ptr[node]]; node=ptr[node]; } } //printf("%f\n",(double)clock()/CLOCKS_PER_SEC); //按父亲排序 //next[n+2..n+n]作为新next,succ[n+1..n]作为新的表头。 //ptr[1..n]是父亲,next[1..n]作为分界点。 memset(succ,0,sizeof(succ)); memset(next,0,sizeof(next)); for(i=1;i<=n;++i)next[i+n]=succ[n+ptr[i]],succ[n+ptr[i]]=n+i; next[1]=1; for(i=1;i<=n;++i){ next[i+1]=next[i]; for(j=succ[n+i];j;j=next[j])succ[next[i+1]++]=j-n; } memset(next+n+3,0,sizeof(int)*n); //printf("%f\n",(double)clock()/CLOCKS_PER_SEC); //求size memset(flag,0,sizeof(flag)); for(i=n;i;--i)succ[n+i]=next[i]; node=1; while(node){ if(succ[n+node]==next[node+1]){ ++next[n+1+node]; flag[node]=1; node=ptr[node]; } else if(!flag[succ[succ[n+node]]])node=succ[succ[n+node]]; else next[n+1+node]+=next[n+1+succ[succ[n+node]++]]; } memset(succ+n+1,0,sizeof(int)*n); //printf("%f\n",(double)clock()/CLOCKS_PER_SEC); //dp DS ans=dfs(1,1); //printf("%f\n",(double)clock()/CLOCKS_PER_SEC); printf("%d\n%I64d\n",ans.f[0],ans.g[0]);}
总结:
①一定要试极限数据啊!!!尤其是模的数有范围的情况!
②如果不是为了位运算还是不要用bitset的好,直接布尔数组快多了。。
③不要用什么沙茶
0 0
- 匹配 解题报告
- 括号匹配问题解题报告
- POJ 1936(字符串匹配) 解题报告
- 洛谷P1739 表达式括号匹配解题报告
- BZOJ3507: [Cqoi2014]通配符匹配 解题报告
- 白话二分匹配之最大匹配+附上hdu2063解题报告
- 解题报告-HDOJ-2063(最大二分匹配-匈牙利算法)
- HDU_1533 Going Home(最优匹配) 解题报告
- 串结构练习——字符串匹配 解题报告
- Leetcode #44. Wildcard Matching 通配符匹配 解题报告
- hdu 2819 Swap 二分图匹配 匈牙利算法 解题报告
- hdu 2063 过山车 二分图匹配 匈牙利算法 解题报告
- 【Noi OpenJudge】 带通配符的字符串匹配 解题报告
- 【九度OJ】题目1153:括号匹配问题 解题报告
- HDU 2063 二分图最大匹配 解题报告
- BZOJ 4950 [Wf 2017] 二分图最大匹配 解题报告
- 解题报告
- 解题报告
- centos 7 u盘安装
- js中的setTimeout与setTimeInterval
- iOS——UITableVew 头部图片下拉放大
- 一、CXF WebService准备工作
- hadoop单机伪分布式环境搭建和mahout试用
- 匹配 解题报告
- 二、CXF 入门示例
- swift类和接口的使用
- 快速幂取模
- caffe框架翻译和理解
- Java 成员初始化过程
- 三、CXF对Interceptor拦截器的支持
- EA建模时,容易混乱的几点
- NGUI出现Shader wants normals, but the mesh UIAtlas doesn't have them