http://www.elijahqi.win/archives/3752
Description
Hnoi2007-Day1有一道题目 Park:给你一个 m * n 的矩阵,每个矩阵内有个
权值V(i,j) (可能为负数),要求找一条回路,使得每个点最多经过一次,并且经过
的点权值之和最大,想必大家印象深刻吧.
无聊的小 C 同学把这个问题稍微改了一下:要求找一条路径,使得每个点
最多经过一次,并且点权值之和最大,如果你跟小 C 一样无聊,就麻烦做一下
这个题目吧.
Input
第一行 m, n,接下来 m行每行 n 个数即.
V( i,j)
Output
一个整数表示路径的最大权值之和.
Sample Input
2 3
1 -2 1
1 1 1
Sample Output
5
【数据范围】
30%的数据,n≤6.
100%的数据,m<=100,n ≤ ≤8.
注意:路径上有可能只有一个点.
HINT
Source
毁我青春 浪费时间
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
return x*f;
}
struct node{
int st,v,next;
}data[2][1<<18];
const int mod=10000;
int h[mod],num[2],pre,cur,mp[110][10],n,m,ans;
inline void trans(int s){
for (int i=0;i<=m;++i){
printf("%d",(s>>(i<<1))%4);
}
}
inline void insert1(int s,int v){
//trans(s);printf(" %d\n",v);
int ss=s%mod;
for (int i=h[ss];i;i=data[cur][i].next){
if (s==data[cur][i].st){
data[cur][i].v=max(data[cur][i].v,v);return;
}
}data[cur][++num[cur]].st=s;data[cur][num[cur]].v=v;data[cur][num[cur]].next=h[ss];h[ss]=num[cur];
}
inline int set(int S,int x,int y,int left,int up){
return S+left*(1<<(x<<1))+up*(1<<(y<<1));
}
inline int getl(int s,int l){
int cnt=1;
for (int i=l;~i;--i){
if ((s>>(i<<1))%4==1) --cnt;
if ((s>>(i<<1))%4==2) ++cnt;
if (!cnt) return i;
}
}
inline int getr(int s,int r){
int cnt=1;
for (int i=r;i<=m;++i){
if ((s>>(i<<1))%4==1) ++cnt;
if ((s>>(i<<1))%4==2) --cnt;
if (!cnt) return i;
}
}
int main(){
freopen("bzoj2310.in","r",stdin);
freopen("bzoj2310.out","w",stdout);
n=read();m=read();
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j) mp[i][j]=read(),ans=max(mp[i][j],ans);
pre=0;cur=1;data[pre][++num[pre]].st=0;data[pre][num[pre]].v=0;
for (int i=1;i<=n;++i){
for (int j=1;j<=num[pre];++j) data[pre][j].st<<=2;//trans(data[pre][j].st);//printf(" %d\n",data[pre][j].v);puts("---");
for (int j=1;j<=m;++j){
num[cur]=0;memset(h,0,sizeof(h));
for (int k=1;k<=num[pre];++k){
int now=data[pre][k].st,v=data[pre][k].v,left=now>>(j-1<<1),up=now>>(j<<1);left%=4;up%=4;
int s=set(now,j-1,j,-left,-up),x;
if (!left&&!up){
insert1(now,v);
if (j!=m) insert1(set(s,j-1,j,0,3),v+mp[i][j]);
if (i!=n) insert1(set(s,j-1,j,3,0),v+mp[i][j]);
if (i!=n&&j!=m) insert1(set(s,j-1,j,1,2),v+mp[i][j]);continue;
}
if (!left||!up){
if (j!=m) insert1(set(s,j-1,j,0,up+left),v+mp[i][j]);
if (i!=n) insert1(set(s,j-1,j,up+left,0),v+mp[i][j]);
if (left+up==1) x=getr(s,j),insert1(set(s,x,x,-2,3),v+mp[i][j]);
if (left+up==2) x=getl(s,j-1),insert1(set(s,x,x,-1,3),v+mp[i][j]);
if (left+up==3) if (!s) ans=max(ans,v+mp[i][j]);continue;
}
if (left==3&&up==3) {if (!s) ans=max(ans,v+mp[i][j]);continue;}
if (left==1&&up==3) x=getr(now,j),insert1(set(s,x,x,-2,3),v+mp[i][j]);
if (left==3&&up==1) x=getr(now,j+1),insert1(set(s,x,x,-2,3),v+mp[i][j]);
if (left==2&&up==3) x=getl(now,j-2),insert1(set(s,x,x,-1,3),v+mp[i][j]);
if (left==3&&up==2) x=getl(now,j-1),insert1(set(s,x,x,-1,3),v+mp[i][j]);
if (left==1&&up==1) x=getr(now,j+1),insert1(set(s,x,x,-2,1),v+mp[i][j]);
if (left==2&&up==2) x=getl(now,j-2),insert1(set(s,x,x,-1,2),v+mp[i][j]);
if (left==2&&up==1) insert1(s,v+mp[i][j]);
}//printf("%d--\n",j);
pre^=1;cur^=1;
}
}printf("%d\n",ans);
return 0;
}