f(i,j,S)表示到(i,j),且经由的路径上的颜色集合为S的价值的最小值,从上方和左方转移过来即可。
要注意,内存不足,需要滚动数组优化,即使用了map,还是需要。
路径输出的时候,可以再跑一遍dp,这样就不用再开一个大数组了。
我的写法比较菜。卡了常数
#include<cstdio> #include<algorithm> #include<map> using namespace std; int w[401][401],c[401][401]; typedef pair<int,int> Point; map<int,int>f[401][401]; typedef pair<int,Point> data; typedef map<int,int>::iterator ITER; map<int,data>g[401][401]; int n,K,W; int calc(int x) { int res=0; while(x) { res+=(x&1); x>>=1; } return res; } Point path[1001]; int e; int main() { scanf("%d%d%d",&n,&K,&W); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) scanf("%d",&w[i][j]); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) scanf("%d",&c[i][j]); if(w[1][1]>W) { puts("-1"); return 0; } f[1][1][1<<(c[1][1]-1)]=w[1][1]; for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j) { if(i>1 && j>1) { for(ITER it=f[i-1][j].begin();it!=f[i-1][j].end();++it) { int nS=(*it).first|(1<<(c[i][j]-1)),tmp=(*it).second+w[i][j]; if(f[i][j].find(nS)==f[i][j].end()) { if(tmp<=W) { f[i][j][nS]=tmp; g[i][j][nS]=data((*it).first,Point(i-1,j)); } } else if(f[i][j][nS]>tmp) { f[i][j][nS]=tmp; g[i][j][nS]=data((*it).first,Point(i-1,j)); } } for(ITER it=f[i][j-1].begin();it!=f[i][j-1].end();++it) { int nS=(*it).first|(1<<(c[i][j]-1)),tmp=(*it).second+w[i][j]; if(f[i][j].find(nS)==f[i][j].end()) { if(tmp<=W) { f[i][j][nS]=tmp; g[i][j][nS]=data((*it).first,Point(i,j-1)); } } else if(f[i][j][nS]>tmp) { f[i][j][nS]=tmp; g[i][j][nS]=data((*it).first,Point(i,j-1)); } } } else if(i==1 && j>1) { for(ITER it=f[i][j-1].begin();it!=f[i][j-1].end();++it) { int nS=(*it).first|(1<<(c[i][j]-1)),tmp=(*it).second+w[i][j]; if(f[i][j].find(nS)==f[i][j].end()) { if(tmp<=W) { f[i][j][nS]=tmp; g[i][j][nS]=data((*it).first,Point(i,j-1)); } } else if(f[i][j][nS]>tmp) { f[i][j][nS]=tmp; g[i][j][nS]=data((*it).first,Point(i,j-1)); } } } else if(i>1 && j==1) { for(ITER it=f[i-1][j].begin();it!=f[i-1][j].end();++it) { int nS=(*it).first|(1<<(c[i][j]-1)),tmp=(*it).second+w[i][j]; if(f[i][j].find(nS)==f[i][j].end()) { if(tmp<=W) { f[i][j][nS]=tmp; g[i][j][nS]=data((*it).first,Point(i-1,j)); } } else if(f[i][j][nS]>tmp) { f[i][j][nS]=tmp; g[i][j][nS]=data((*it).first,Point(i-1,j)); } } } } if(i>=3) { for(int j=1;j<=n;++j) { f[i-2][j].clear(); // g[i-2][j]. } } } int ans=2147483647; int anS; for(ITER it=f[n][n].begin();it!=f[n][n].end();++it) { int tmp=calc((*it).first); if(tmp<ans) { ans=tmp; anS=(*it).first; } } if(ans==2147483647) puts("-1"); else { printf("%d\n",ans); data U=data(anS,Point(n,n)); path[++e]=Point(n,n); while(U.second!=Point(1,1)) { U=g[U.second.first][U.second.second][U.first]; path[++e]=U.second; } for(int i=e;i>=1;--i) printf("%d %d%c",path[i].first,path[i].second,i==1 ? ‘\n‘ : ‘ ‘); } return 0; }
时间: 2024-10-11 17:05:33