【BZOJ】1187: [HNOI2007]神奇游乐园
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1187
每个格子都具有权值,求任意一个回路使得路径上的权值和最大。
裸的插头DP,注意一下几点:
1.因为不一定要全部格子都要走过,所以可以空一格不走,前提这个状态是没有上插头和左插头的。
2.每个格子都应该可以作为起始状态(新建连通块)。
3.关于形成回路的状态显然不能再往下转移,同时如果这个的轮廓线上除了左插头和右插头之外没有插头了,可以算入答案。
QwQ...细节还是看代码吧。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8 using namespace std; 9 #define maxn 10010 10 #define llg long long 11 #define sizee 57 12 #define maxZT (1<<18) 13 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); 14 llg n,m,now,size[2],zt[2][maxZT],ans,la,code[maxn],quan; 15 llg v[2][maxZT]; 16 17 struct node 18 { 19 llg x,val,pos; 20 }; 21 22 vector<node>a[2][sizee]; 23 24 void outcode(llg x) {for (llg i=0;i<=m;i++) code[i]=x&3,x>>=2;} 25 26 void encode(llg p,llg val) 27 { 28 llg x=0; 29 for (llg i=0;i<=m;i++) x+=code[i]*(1<<(i*2)); 30 llg wz=x%sizee,E=a[p][wz].size(); 31 for (llg i=0;i<E;i++) 32 if (a[p][wz][i].x==x) 33 { 34 a[p][wz][i].val=max(a[p][wz][i].val,val); 35 v[p][a[p][wz][i].pos]=max(v[p][a[p][wz][i].pos],val); 36 return ; 37 } 38 size[p]++; 39 node NEW; NEW.x=x; NEW.val=val; NEW.pos=size[p]; 40 a[p][wz].push_back(NEW); 41 zt[p][size[p]]=x; v[p][size[p]]=val; 42 } 43 44 void init_a(llg p){for (llg i=0;i<sizee;i++) a[p][i].clear(); size[p]=0;} 45 46 void DP() 47 { 48 llg now=0; 49 encode(0,0); 50 for (llg i=1;i<=n;i++) 51 { 52 for (llg k=1;k<=size[now];k++) zt[now][k]*=4; 53 for (llg j=1;j<=m;j++) 54 { 55 scanf("%lld",&quan); 56 now^=1; la=now^1; size[now]=0; 57 init_a(now); 58 for (llg k=1;k<=size[la];k++) 59 { 60 outcode(zt[la][k]); 61 llg le=code[j-1],up=code[j],V=v[la][k]; 62 63 if (!le && !up) //空格 64 { 65 encode(now,V); 66 } 67 //------------------------------------------------------------------------------------- 68 if (!le && !up)//没有插头,新建连通分量 69 { 70 if (j<m) 71 { 72 code[j-1]=1,code[j]=2; 73 encode(now,V+quan); 74 } 75 continue; 76 } 77 //------------------------------------------------------------------------------------- 78 if (!le && up)//延续上插头 79 { 80 if (j<m) encode(now,V+quan); 81 code[j-1]=code[j]; code[j]=0; 82 encode(now,V+quan); 83 continue; 84 } 85 //------------------------------------------------------------------------------------- 86 if (le && !up)//延续左插头 87 { 88 encode(now,V+quan); 89 if (j<m) 90 { 91 code[j]=code[j-1]; code[j-1]=0; 92 encode(now,V+quan); 93 } 94 continue; 95 } 96 //------------------------------------------------------------------------------------- 97 if (le==1 && up==2)//回路闭合,统计答案 98 { 99 bool pd=true; 100 for (llg e=0;e<j-1;e++) if (code[e]) pd=false; 101 for (llg e=j+1;e<=m;e++) if (code[e]) pd=false; 102 if (pd) ans=max(ans,V+quan); 103 // if (pd) cout<<i<<" "<<j<<"--->"<<V+quan<<endl; 104 continue; 105 } 106 //------------------------------------------------------------------------------------- 107 if (le==2 && up==1)//左插头为右括号,上插头为左括号,直接合并 108 { 109 code[j]=code[j-1]=0; 110 encode(now,V+quan); 111 continue; 112 } 113 //------------------------------------------------------------------------------------- 114 if (le==1 && up==1)//上左插头均为左括号,找到上插头所对应的右括号并将其修改为左括号 115 { 116 for (llg e=j+1;e<=m;e++) 117 if (code[e]==2) 118 { 119 code[e]=1; 120 break; 121 } 122 code[j]=code[j-1]=0; 123 encode(now,V+quan); 124 continue; 125 } 126 //------------------------------------------------------------------------------------- 127 if (le==2 && up==2)//上左插头均为右括号,找到左插头对应的左括号并将其修改为右括号 128 { 129 for (llg e=j-2;e>=0;e--) 130 if (code[e]==1) 131 { 132 code[e]=2; 133 break; 134 } 135 code[j]=code[j-1]=0; 136 encode(now,V+quan); 137 continue; 138 } 139 } 140 } 141 } 142 } 143 144 int main() 145 { 146 yyj("a"); 147 ans=-1*0x7fffffff; 148 cin>>n>>m; 149 DP(); 150 cout<<ans; 151 return 0; 152 }
本文作者:xrdog
作者博客:http://www.cnblogs.com/Dragon-Light/
转载请注明出处,侵权必究,保留最终解释权!