C o d e Code Code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=21; int dp[2][1<<N],n,v; void solve(){ memset(dp,0,sizeof(dp)); int pre=0,now=1; dp[pre][0]=0; int ans=0; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ scanf("%d",&v); for(int S=0;S<(1<<n);S++){//轮廓线状态 int newS=S&(~(1<<j)); dp[now][newS]=max(dp[now][newS],dp[pre][S]); if((S&(1<<j))==0&&(j==0||(S&(1<<(j-1)))==0))//上面和左均为0,可以取数 dp[now][S|(1<<j)]=max(dp[now][S|(1<<j)],dp[pre][S]+v); } swap(pre,now); } } for(int S=0;S<(1<<n);S++) ans=max(ans,dp[pre][S]); printf("%d\n",ans); } int main(){ while(~scanf("%d",&n)){ solve(); } return 0; }我们大多数人都知道,在名为DotA(古代防御)的游戏中, 帕吉在游戏的第一阶段是一个强大的英雄。但是,当游戏结束时,帕吉不再是一个强大的英雄。 因此,帕吉(Pudge)的队友为他分配了新任务-吃树! 这些树的大小为N * M个矩形,每个单元要么只有一棵树,要么根本没有。帕吉要做的就是吃掉牢房里的所有树木。 Pudge必须遵循以下几条规则: I.帕吉必须选择回路来吃掉树木,然后他才能吃掉所选回路中的所有树木。 二。不包含树的单元格无法访问,例如通过Pudge选择的通过回路的每个单元必须包含一棵树,并且当选择回路时,回路中单元中的树将消失。 三,帕吉人可以选择一个或多个回路来吃树。 现在帕吉有一个问题,那里有几种吃树的方法? 在下面的图片中,给出了N = 6和M = 3的三个样本(灰色正方形表示单元中没有树,黑色粗线表示所选的电路)
C o d e Code Code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; long long dp[2][1<<12]; long long ans; int n,m,v; void solve(){ int total=1<<(m+1); int pre=0,now=1; memset(dp[pre],0,sizeof(dp[pre])); dp[pre][0]=1; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ scanf("%d",&v); memset(dp[now],0,sizeof(dp[now])); int j0=1<<j; int j1=j0<<1; for(int S=0;S<total;S++){ bool p=S&j0,q=S&j1;//前一个格子的左,上状态 if(v==0){//障碍物,不可行 if(!p&&!q) dp[now][S]+=dp[pre][S]; }else{ if(p^q)//有一个为1,一个为0 dp[now][S]+=dp[pre][S];//原状态不变 dp[now][S^j0^j1]+=dp[pre][S];//相反状态 } } swap(pre,now);//处理完一个格子后交换 } memset(dp[now],0,sizeof(dp[now]));//为处理下一行做准备 for(int S=0;S<total/2;S++)//最后的状态最大0111...1 dp[now][S<<1]=dp[pre][S];//也可以+=,速度更快15ms,=,46ms swap(pre,now);//交换后的pre是处理过的结果,为下一行做准备 } ans=dp[now][0]; } int main(){ int T,cas=1; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); solve(); printf("Case %d: There are %I64d ways to eat the trees.\n",cas++,ans); } return 0; }一个正方形城镇已被划分为n * m(n行和m列)平方图(1 <= N,M <= 8),其中一些被阻塞,其他未被阻塞。农场位于左下图,市场位于右下图。托尼(Tony)沿着每一个畅通无阻的地块走了一次,从农场到集市进行了整个小镇之旅。 编写一个程序,计算Betsy从农场到市场可以带多少次独特的旅行。
C o d e Code Code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define LL long long LL dp[2][1<<20];//记录方案数 int state[2][1<<20];//记录状态,S=state[pre][s],pre为前一个格子标记,s为状态编号,S为状态 int total[2];//记录状态总数 int pre,now; int endx,endy;//记录最后一个非障碍格子 bool map[15][15]; char str[200]; int m,n; LL ans; const int HASH=4001;//坑点!!哈希值太大会超时!本题m<=10,用4位数素数,如3007,5位素数时间更多 int Hash[HASH];//记录S对应的哈希值x的状态编号 void HashIn(int S,LL num){ int x=S%HASH; while(~Hash[x]&&state[now][Hash[x]]!=S){//线性探测 x++; x%=HASH; } if(Hash[x]==-1){//未找到,加入hash表中 dp[now][total[now]]=num; state[now][total[now]]=S; Hash[x]=total[now];//记录状态编号 total[now]++; } else//找到,累加方案数 dp[now][Hash[x]]+=num; } void init(){ memset(map,0,sizeof(map)); endx=-1; for(int i=0;i<n;i++){ scanf("%s",str); for(int j=0;j<m;j++){ if(str[j]=='.'){ map[i][j]=1; endx=i; endy=j; } else map[i][j]=0; } } if(map[n-1][0]==0||map[n-1][m-1]==0)//最后一行的左角或右角不可达 endx=endy=-1; else{ endx=n+1; endy=m-1; } for(int j=0;j<m;j++){//增加两行,第一行首尾可行,其它不可行,第二行均可行 map[n][j]=0; map[n+1][j]=1; } map[n][0]=map[n][m-1]=1; n+=2;//注意 这里将矩形扩大 方便后面的使用 } //位运算,取S按长度l的第p位 int getV(int S,int p,int l=2){//4进制,l=2;8进制,l=3 return (S>>(p*l))&((1<<l)-1); } //位运算,设置S按长度l的第p位值为v void setV(int& S,int p,int v,int l=2){ S^=getV(S,p)<<(p*l);//第p位置0 S|=v<<(p*l);//第p位置v } void memsetnow(){//哈希每次用后清空 memset(Hash,-1,sizeof(Hash)); total[now]=0; } void solve(){ init(); if(endx==-1){ puts("0"); return; } pre=0,now=1; ans=0; memsetnow(); dp[pre][0]=1; state[pre][0]=0; total[pre]=1; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ memsetnow(); for(int s=0;s<total[pre];s++){//s为状态编号 if(dp[pre][s]) { LL num=dp[pre][s]; int S=state[pre][s]; int p=getV(S,j); int q=getV(S,j+1); if(map[i][j]==0){//有障碍 if(p==0&&q==0) HashIn(S,num); continue; } if(p==0&&q==0){//p、q均为0,第一种情况 if(map[i+1][j]&&map[i][j+1]){ int nS=S; setV(nS,j,1); setV(nS,j+1,2); HashIn(nS,num); } continue; } if((p>0)^(q>0)){//p、q有一个为0,第二种情况 if(map[i+(p>0)][j+(q>0)]) HashIn(S,num); if(map[i+(q>0)][j+(p>0)]){ int nS=S; setV(nS,j,q);//p、q交换 setV(nS,j+1,p); HashIn(nS,num); } continue; } if(p==1&&q==1){//第三种情况,3.1 int find=1; for(int v=j+2;v<=m;v++){//向后搜q匹配的右括号),改为左括号 int k=getV(S,v); if(k==1) find++; else if(k==2) find--; if(find==0){ int nS=S; setV(nS,j,0);//p、q置0 setV(nS,j+1,0); setV(nS,v,1);//改为左括号 HashIn(nS,num); break; } } continue; } if(p==2&&q==2){//第三种情况,3.2 int find=1; for(int v=j-1;v>=0;v--){//向前搜p匹配的左括号(,改为右括号 int k=getV(S,v); if(k==2) find++; else if(k==1) find--; if(find==0){ int nS=S; setV(nS,j,0);//p、q置0 setV(nS,j+1,0); setV(nS,v,2);//改为右括号 HashIn(nS,num); break; } } continue; } if(p==2&&q==1){//第三种情况,3.3 int nS=S; setV(nS,j,0);//p、q置0 setV(nS,j+1,0); HashIn(nS,num); continue; } if(p==1&&q==2){//第三种情况,3.4 if(i==endx&&j==endy)//最后一个非障碍格子 ans+=num; } } } swap(now,pre); } memsetnow(); for(int s=0;s<total[pre];s++) if(dp[pre][s]){ LL num=dp[pre][s]; int S=state[pre][s]<<2;//左移一格 HashIn(S,num); } swap(now,pre); } printf("%I64d\n",ans); } int main(){ while(~scanf("%d%d",&n,&m),n+m){ if(n==1&&m==1){//只有一格特殊处理 scanf("%s",str); if(str[0]=='.') printf("1\n"); else printf("0\n"); continue; }else if(m==1){//只有一列多行的情况 int ok=1; for(int i=0;i<n;i++){ scanf("%s",str); if(str[0]=='.'&&i<n-1) ok=0; } if(str[0]=='#') ok=0; printf("%d\n",ok); continue; } solve(); } return 0; }谁会足够聪明地制定电路规划并让城市免受不可避免的耻辱?当然,只有真正的专业人员-本地技术大学一线团队中经过战斗的程序员!..但是我们的英雄们并没有在寻找轻松的生活,而是提出了更加困难的问题:“当然,如果我们找到了,我们的市长会很高兴的。有多少种构建电路的方法!” - 他们说。 应该说,沃洛格达州的赛道将非常简单。这将是一个大小为N * M的矩形单元,每个单元都构建一个单个电路段。每个线段应平行于矩形的一侧,因此电路上只能有直角的弯曲。在下面的图片中,给出了两个样本,其中N = M = 4(灰色正方形表示地鼠孔,粗黑线表示竞赛电路)。这里没有其他方法可以构建电路。
C o d e Code Code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define LL long long LL dp[2][1<<24];//记录方案数 int state[2][1<<24];//记录状态,S=state[pre][s],pre为前一个格子标记,s为状态编号,S为状态 int total[2];//记录状态总数 int pre,now; int endx,endy;//记录最后一个非障碍格子 bool map[15][15]; int m,n; LL ans; const int HASH=40001;//坑点!!哈希值太小会超时!4位素数超时,m<=12,用5位数素数,如30007 int Hash[HASH];//记录S对应的哈希值x的状态编号 void HashIn(int S,LL num){ int x=S%HASH; while(~Hash[x]&&state[now][Hash[x]]!=S){//线性探测 x++; x%=HASH; } if(Hash[x]==-1){//未找到,加入hash表中 dp[now][total[now]]=num; state[now][total[now]]=S; Hash[x]=total[now];//记录状态编号 total[now]++; } else//找到,累加方案数 dp[now][Hash[x]]+=num; } void init(){ memset(map,0,sizeof(map)); endx=-1; for(int i=0;i<n;i++){ char str[200]; scanf("%s",str); for(int j=0;j<m;j++){ if(str[j]=='*') map[i][j]=0; else if(str[j]=='.'){ map[i][j]=1; endx=i; endy=j; } } } } //位运算,取S按长度l的第p位 int getV(int S,int p,int l=2){//4进制,l=2;8进制,l=3 return (S>>(p*l))&((1<<l)-1); } //位运算,设置S按长度l的第p位值为v void setV(int& S,int p,int v,int l=2){ S^=getV(S,p)<<(p*l);//第p位置0 S|=v<<(p*l);//第p位置v } void memsetnow(){//哈希表清空 memset(Hash,-1,sizeof(Hash)); total[now]=0; } void solve() { init(); if(endx==-1){ puts("0"); return; } pre=0,now=1; ans=0; memsetnow();//哈希表清空 dp[pre][0]=1; state[pre][0]=0; total[pre]=1; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ memsetnow();//哈希表清空 for(int s=0;s<total[pre];s++){ if(dp[pre][s]){ LL num=dp[pre][s]; int S=state[pre][s]; int p=getV(S,j); int q=getV(S,j+1); if(map[i][j]==0){//有障碍,第一种情况 if(p==0&&q==0) HashIn(S,num); continue; } if(p==0&&q==0){//p、q均为0,第二种情况 if(map[i+1][j]&&map[i][j+1]){ int nS=S; setV(nS,j,1); setV(nS,j+1,2); HashIn(nS,num); } continue; } if((p>0)^(q>0)){//p、q有一个为0,第三种情况 if(map[i+(p>0)][j+(q>0)]) HashIn(S,num); if(map[i+(q>0)][j+(p>0)]){ int nS=S; setV(nS,j,q);//p、q交换 setV(nS,j+1,p); HashIn(nS,num); } continue; } if(p==1&&q==1){//第四种情况,4.1 int find=1; for(int v=j+2;v<=m;v++){//向后搜q匹配的右括号),改为左括号 int k=getV(S,v); if(k==1) find++; else if(k==2) find--; if(find==0){ int nS=S; setV(nS,j,0);//p、q置0 setV(nS,j+1,0); setV(nS,v,1);//改为左括号 HashIn(nS,num); break; } } continue; } if(p==2&&q==2){//第四种情况,4.2 int find=1; for(int v=j-1;v>=0;v--){//向前搜p匹配的左括号(,改为右括号 int k=getV(S,v); if(k==2) find++; else if(k==1) find--; if(find==0){ int nS=S; setV(nS,j,0);//p、q置0 setV(nS,j+1,0); setV(nS,v,2);//改为右括号 HashIn(nS,num); break; } } continue; } if(p==2&&q==1){//第四种情况,4.3 int nS=S; setV(nS,j,0);//p、q置0 setV(nS,j+1,0); HashIn(nS,num); continue; } if(p==1&&q==2){//第四种情况,4.4 if(i==endx&&j==endy)//最后一个非障碍格子 ans+=num; } } } swap(now,pre); } memsetnow();//哈希表清空 for(int s=0;s<total[pre];s++) if(dp[pre][s]){ LL num=dp[pre][s]; int S=state[pre][s]<<2;//左移一格,四进制,一格用两位表示 HashIn(S,num); } swap(now,pre); } printf("%I64d\n",ans); } int main(){ while(~scanf("%d%d",&n,&m)){ solve(); } return 0; }