原题链接:Codeforces 142C. Help Caretaker
题目大意:给定一个\(n\cdot m\)的矩阵,每次可以摆一个T字(T的形状见原题面),这些T不能交叉重叠,问在一个\(n\cdot m\)的矩阵中最多可以摆多少个T字。
题解:先来口胡一下本题我一共试过三种方法:
(1)打表(连方案一起打下来,反正一共就\(9\times 9\)个,够了。
(2)暴力dfs,一眼就能看出来解法的,再加上一点点剪枝,就没有了。
(3)运用状态压缩,记录下最近三行的状态,用map记录一下,搜索就可以了。口胡完毕,大佬们可以离开了
好了,我先来讲一下我的两种做法:
(1)暴力dfs,加上一个玄学牺牲了正确性的剪枝,然后很惊奇地发现在\(9\times 8\)和\(8\times 9\)的情况下会WA,便用暴力加了一个表。
暴力的思路应该不用讲了,接下来就看一下代码吧。
my code
#include <cstdio>
char mp[15][15];
int n,m;
int ans;
char an[15][15];
const int d[4][5][2]={{{0,0},{0,1},{0,2},{1,1},{2,1}},{{0,2},{1,0},{1,1},{1,2},{2,2}},{{0,1},{1,1},{2,0},{2,1},{2,2}},{{0,0},{1,0},{1,1},{1,2},{2,0}}};//增量表
void dfs(int x,int y,int num,int use){
if(y==m+1){
x++;
y=1;
}
if(((n*m-use))/5+num<=ans){
return;
}
if(x>n){
if(num>ans){
ans=num;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
an[i][j]=mp[i][j];
}
}
}
return;
}
if(mp[x][y]=='.'){
use++;
}
dfs(x,y+1,num,use);
bool could;
int nx,ny;
for(int i=0;i<4;i++){
could=1;
for(int j=0;j<5;j++){
nx=x+d[i][j][0];
ny=y+d[i][j][1];
if(nx<1||ny<1||nx>n||ny>m||mp[nx][ny]!='.'){
could=0;
break;
}
}
if(!could){
continue;
}
for(int j=0;j<5;j++){
nx=x+d[i][j][0];
ny=y+d[i][j][1];
mp[nx][ny]=(char)(num+'A');
}
dfs(x,y+1,num+1,use+5);
for(int j=0;j<5;j++){
nx=x+d[i][j][0];
ny=y+d[i][j][1];
mp[nx][ny]='.';
}
}
}
int main(){
scanf("%d%d",&n,&m);
if(n==9&&m==8){
printf("%d\n",12);
puts(".AAABCCC");
puts(".DA.B.C.");
puts(".DABBBCE");
puts("DDDFGEEE");
puts("HFFFGGGE");
puts("HHHFGIII");
puts("HJKKKLI.");
puts(".J.K.LI.");
puts("JJJKLLL.");
return 0;
}
if(n==8&&m==9){
printf("%d\n",12);
puts("...ABBB.C");
puts("DAAAEBCCC");
puts("DDDAEBF.C");
puts("D.GEEEFFF");
puts("GGGHHHF.I");
puts("J.GKHLIII");
puts("JJJKHLLLI");
puts("J.KKKL...");
return 0;
}
for(int x=1;x<=n;x++){
for(int y=1;y<=m;y++){
mp[x][y]='.';
an[x][y]='.';
}
}
ans=0;
dfs(1,1,0,0);
printf("%d\n",ans);
for(int x=1;x<=n;x++){
for(int y=1;y<=m;y++){
putchar(an[x][y]);
}
puts("");
}
return 0;
}
(2)感觉有点悬那,正式考试时貌似很慌啊,还是老老实实打状压吧。
思路:记忆化搜索,怎么记忆化呢?我们令\(f[x][y][mask]\)为当前在第\(x\) 行,第\(y\)列,前三行状态为\(mask\)时,后面最多能摆多少个T。
话说,暴力的代码是正好写,但这个嘛……位运算的基础一定要好。
my code
#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;
#define par pair<pair<int,int>,int>
#define make_par(a,b,c) make_pair(make_pair(a,b),c)
const int d[4][5][2]={{{-2,-2},{-2,-1},{-2,0},{-1,-1},{0,-1}},{{-2,0},{-1,-2},{-1,-1},{-1,0},{0,0}},{{-2,-1},{-1,-1},{0,-2},{0,-1},{0,0}},{{-2,-2},{-1,-2},{-1,-1},{-1,0},{0,-2}}};//同上
map<par,int> mp;
int n,m;
int find(int x,int y,int nx,int ny){
return 1<<((x-nx)*m+y-ny);
}
int mx(int a,int b){
return a>b?a:b;
}
int dfs(int x,int y,int mask){
if(mask&(1<<28)){
mask^=(1<<28);
}
if(mask&(1<<29)){
mask^=(1<<29);
}
if(mask&(1<<30)){
mask^=(1<<30);
}
par now=make_par(x,y,mask);
if(mp.count(now)>0){
return mp[now];
}
int &ans=mp[now]=0;
if(y>m){
y=1;
x++;
}
if(x>n){
return ans=0;
}
ans=dfs(x,y+1,mask<<1);
int nx,ny;
int nmask;
int _now;
bool could;
if(y<=2){
return ans;
}
for(int i=0;i<4;i++){
nmask=mask;
nmask<<=1;
could=1;
for(int j=0;j<5;j++){
nx=x+d[i][j][0];
ny=y+d[i][j][1];
if(nx<1||ny<1||nx>n||ny>m){
could=0;
break;
}
_now=find(x,y,nx,ny);
if(mask&(_now>>1)){
could=0;
break;
}
nmask|=_now;
}
if(could){
ans=mx(ans,dfs(x,y+1,nmask)+1);
}
}
return ans;
}
char s[15][15];
bool found(int x,int y,int mask,int res){
if(y>m){
y=1;
x++;
}
if(res==0){
return 1;
}
if(x>n){
return res==0;
}
if(dfs(x,y+1,mask<<1)>=res&&found(x,y+1,mask<<1,res)){
return 1;
}
int nx,ny;
int nmask;
int _now;
bool could;
for(int i=0;i<4;i++){
nmask=mask;
nmask<<=1;
could=1;
for(int j=0;j<5;j++){
nx=x+d[i][j][0];
ny=y+d[i][j][1];
if(nx<1||ny<1||nx>n||ny>m){
could=0;
break;
}
_now=find(x,y,nx,ny);
if(mask&(_now>>1)){
could=0;
break;
}
nmask|=_now;
}
if(could){
if(dfs(x,y+1,nmask)<res-1){
continue;
}
for(int j=0;j<5;j++){
nx=x+d[i][j][0];
ny=y+d[i][j][1];
s[nx][ny]=res+'A'-1;
}
if(found(x,y+1,nmask,res-1)){
return 1;
}
for(int j=0;j<5;j++){
nx=x+d[i][j][0];
ny=y+d[i][j][1];
s[nx][ny]='.';
}
}
}
return 0;
}
int main(){
scanf("%d%d",&n,&m);
if(n<3||m<3){
puts("0");
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
putchar('.');
}
puts("");
}
return 0;
}
int ans=dfs(3,1,0);
printf("%d\n",ans);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
s[i][j]='.';
}
}
found(3,1,0,ans);
for(int i=1;i<=n;i++){
puts(s[i]+1);
}
puts("");
return 0;
}
我的思路讲完了,接下来来看一下CF上各路神仙的解法吧,真的是……。
我们先来看一下fhlasek的解法:
他的代码很明显的一个暴力dfs+剪枝,但思路和我上面的dfs完全不一样。
思路:对于一个地图,我们枚举在哪一个上面放上一个T,如果可以放,就放了,放下去之后,再往下走一格,试着放一放,放得下,就放,再跳出,放不下,就跳出。
这个dfs的效率奇高,最慢的点只有128ms,(比我写的状压快多了)。
但我弄不明白为什么他要在程序中打一个表呢?我试着把表删去,再交一遍,同样是AC,那么,目的就出来啦:是为了将200ms以上的点变为30ms。不过真有这么重要么
下面是代码:
/* Writen by Filip Hlasek 2011 */
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <algorithm>
#include <cmath>
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define REP(i,b) for(int i=0;i<b;i++)
using namespace std;
char u[10][10],b[10][10];
int N,M,best;
bool ok(int x,int y){
return x>=0&&y>=0&&x<N&&y<M&&u[x][y]=='.';
}
int D[4][5][2]={{{0,0},{1,0},{2,0},{0,1},{0,-1}},
{{0,0},{-1,0},{-2,0},{0,1},{0,-1}},
{{0,0},{0,1},{0,2},{1,0},{-1,0}},
{{0,0},{0,-1},{0,-2},{1,0},{-1,0}}};
void dfs(int depth){
if(depth > best){
best=depth;
REP(i,N) REP(j,M+1) b[i][j]=u[i][j];
}
bool found = false;
int cntfound = 0;
REP(x,N){
REP(y,M){
if(found) cntfound++;
if(cntfound > 2) return;
REP(S,4){
bool uok = true;
REP(d,5) if(!ok(x+D[S][d][0],y+D[S][d][1])) uok=false;
if(!uok) continue;
found = true;
REP(d,5) u[x+D[S][d][0]][y+D[S][d][1]]='A'+depth;
dfs(depth+1);
REP(d,5) u[x+D[S][d][0]][y+D[S][d][1]]='.';
}
}
}
}
int main(int argc, char *argv[]){
scanf("%d%d",&N,&M);
if(N==9&&M==9){
printf("13\nAAABBBCCC\n.AD.BE.C.\n.AD.BE.C.\nFDDDEEE.H\nFFFGGGHHH\nFIIIGJJJH\n.LIKG.JM.\n.LIKKKJM.\nLLLK..MMM\n");
return 0;
}
if(N==9&&M==8){
printf("12\nAAABBB.C\n.AD.BCCC\n.AD.B.EC\nFDDDEEE.\nFFFGGGEI\nFHHHGIII\n.KHJG.LI\n.KHJJJL.\nKKKJ.LLL\n");
return 0;
}
REP(i,N) REP(j,M) u[i][j]='.';
REP(i,N) u[i][M]='\0';
REP(i,N) REP(j,M+1) b[i][j]=u[i][j];
best=0;
dfs(0);
printf("%d\n",best);
REP(i,N) printf("%s\n",b[i]);
return 0;
}
接下来的解法是来自pavel的:
思路:暴力dfs+剪枝,(1)如果剩下的格子个数除以5下取整加上当前的答案还没有当前更新的最终答案要大,就可以return了,(2)如果剩下的格子去掉2行2列之后剩下的格子数加上当前答案还没有当前的最终答案大,就可以return了。思路很好理解,代码也很好实现。
下面是代码:
#define mp make_pair
#define pb push_back
#define setval(a,v) memset(a,v,sizeof(a))
#if ( _WIN32 || __WIN32__ )
#define LLD "%I64d"
#else
#define LLD "%lld"
#endif
using namespace std;
typedef long long ll;
typedef long double ld;
char s[10][10];
char bs[10][10];
int ans;
int start = clock();
const int dx[4][5] = {{0,1,2,1,1},{0,1,2,2,2},{1,1,0,1,2},{0,0,1,2,0}};
const int dy[4][5] = {{0,0,0,1,2},{1,1,0,1,2},{0,1,2,2,2},{0,1,1,1,2}};
int n,m;
bool q,q1;
void dfs(int x,int y,int cur){
if (cur == ans){
memcpy(bs,s,sizeof(bs));
q = q1 = true;
return;
}
if (x >= n-2){
if (clock() - start > 2.7*CLOCKS_PER_SEC)
q = true, q1 = false;
return;
}
if (y >= m-2){
dfs(x+1,0,cur);
return;
}
if (((m-y+1)+(n-x)*m)/5 + cur <= ans)
return;
if ((m-y-1)+(n-x-2)*m+cur <= ans)
return;
for (int i = 0; i < 4; i++){
bool ok = !q;
for (int j = 0; j < 5; j++)
ok &= s[x+dx[i][j]][y+dy[i][j]] == 0;
if (ok){
for (int j = 0; j < 5; j++)
s[x+dx[i][j]][y+dy[i][j]] = 'A'+cur;
dfs(x,y+1,cur+1);
for (int j = 0; j < 5; j++)
s[x+dx[i][j]][y+dy[i][j]] = 0;
}
}
if (!q)
dfs(x,y+1,cur);
}
int main()
{
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d %d",&n,&m);
if (n > 2 && m > 2){
for (ans = 0; ; ans++){
cerr << ans << endl;
q = q1= false;
dfs(0,0,0);
if (!q1){
ans--;
break;
}
}
}
printf("%d\n",ans);
for (int i = 0; i < n; i++,printf("\n"))
for (int j = 0; j < m; j++)
if (bs[i][j] == 0)
printf(".");
else
printf("%c",bs[i][j]);
return 0;
}
接下来看Fefer_Ivan巨佬的:
思路:这一位和上面pavel巨佬的解法思路差不多,并且他的代码还没有第(2)个剪枝,但是他十分有个性地用了一个状态压缩,把一整张地图的每一列压成了一个int,让后就很华丽丽地将dfs中的时间复杂度从\(O(9\cdot 4)\)优化到了\(O(4)\),但是思维复杂度就迅速地往上涨。
下面是代码:
#include <algorithm>
#include <functional>
#include <numeric>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <cassert>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <bitset>
#include <sstream>
using namespace std;
#define forn(i, n) for(int i = 0; i < int(n); ++i)
#define for1(i, n) for(int i = 1; i <= int(n); ++i)
#define ford(i, n) for(int i = int(n) - 1; i >= 0; --i)
#define fore(i, l, r) for(int i = int(l); i < int(r); ++i)
#define sz(v) int((v).size())
#define all(v) (v).begin(), (v).end()
#define pb push_back
#define X first
#define Y second
typedef long long li;
typedef long double ld;
typedef pair<int, int> pt;
template<typename T> T abs(T a) { return a < 0 ? -a : a; }
template<typename T> T sqr(T a) { return a*a; }
const int INF = (int)1e9;
const ld EPS = 1e-9;
const ld PI = 3.1415926535897932384626433832795;
//const int ch[] = {3, 3, };
int n, m;
int used[20];
int t[20][20];
int cur;
int ans;
int ax[20], ay[20], ar[20];
int cx[20], cy[20], cr[20];
char f[20][20];
inline bool check(int x, int y, int* a){
return ((used[x] >> y) & a[0]) == 0 &&
((used[x + 1] >> y) & a[1]) == 0 &&
((used[x + 2] >> y) & a[2]) == 0;
}
const int MAGIC = 80000000;
int curIter;
void solve(int x, int y){
if(x + 3 > n){
if(ans < cur){
ans = cur;
memcpy(ax, cx, sizeof(int)*ans);
memcpy(ay, cy, sizeof(int)*ans);
memcpy(ar, cr, sizeof(int)*ans);
}
return;
}
if(y + 3 > m)
return solve(x + 1, 0);
if(5*(ans - cur + 1) > (n - x - 1)*m + m - y)
return;
if(curIter > MAGIC)
return;
curIter++;
forn(i, 4)
if(check(x, y, t[i])){
for(int j = x; j < x + 3; ++j)
used[j] |= (t[i][j - x] << y);
cx[cur] = x;
cy[cur] = y;
cr[cur] = i;
cur++;
solve(x, y + 1);
cur--;
for(int j = x; j < x + 3; ++j)
used[j] ^= (t[i][j - x] << y);
}
solve(x, y + 1);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt", "rt", stdin);
//freopen("output.txt", "wt", stdout);
#endif
t[0][0] = 7;
t[0][1] = 2;
t[0][2] = 2;
t[1][0] = 4;
t[1][1] = 7;
t[1][2] = 4;
t[2][0] = 2;
t[2][1] = 2;
t[2][2] = 7;
t[3][0] = 1;
t[3][1] = 7;
t[3][2] = 1;
cin >> n >> m;
solve(0, 0);
cout << ans << endl;
char c = 'A';
forn(i, n)
forn(j, m)
f[i][j] = '.';
forn(i, ans){
int x = ax[i];
int y = ay[i];
int r = ar[i];
forn(j, 3)
forn(k, 3)
if((t[r][j] >> k) & 1)
f[x + j][y + k] = c;
++c;
}
forn(i, n)
printf("%s\n", f[i]);
cerr << clock() << endl;
return 0;
}
接下来这一段是ir5的思路+代码:
思路:说真心话,我在翻到他的代码的时候,第一反应是:这是这一题的代码么!
好吧,这一个思路嘛,最重要的就是信仰,代码分为两个步骤完成,第一个步骤是计算出最小值,第二个步骤是计算出方案。我先透露一下啊,这一个代码的正确性是很难保证的,没准你哪次rp极低,交上去就WA了呢。
预处理一下,如果我在当前的地方放了一个某种形状的T,那有多少个地方不能某种形状的T,把全部存起来。
然后,随机的摆一些不重复的T,直到不能摆为止。是不是很玄学啊,如果有点懵逼的话先看一下代码把。
然后进行计算方案,暴力,加上根据预处理以及答案得出的最优性及可行性剪枝,就可以了。
看代码吧:(能想出这种解法的真是神仙)
#include <cstdio>
#include <cstring>
#include <cstdlib>
// #include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cassert>
using namespace std;
typedef long long ll;
#define REP(i,n) for (int i=0; i<(int)(n); ++i)
#define FOR(i,k,n) for (int i=(k); i<(int)(n); ++i)
#define FOREQ(i,k,n) for (int i=(k); i<=(int)(n); ++i)
#define FORIT(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define SZ(v) (int)((v).size())
#define MEMSET(v,h) memset((v),(h),sizeof(v))
const int dip[4][5][2] = {
{
{0, 0},
{0, 1},
{0, 2},
{1, 1},
{2, 1},
},
{
{0, 2},
{1, 0},
{1, 1},
{1, 2},
{2, 2},
},
{
{0, 1},
{1, 1},
{2, 0},
{2, 1},
{2, 2},
},
{
{0, 0},
{1, 0},
{1, 1},
{1, 2},
{2, 0},
},
};
typedef vector<int> V;
int N, M;
int code(int y, int x, int r) {
return 4*(y*(M-2)+x)+r;
}
int K;
vector<V> vg;
int res;
bool f[300], h[300], g[300];
void solve(int idx, int cur) {
int rest=0;
FOR(i, idx, K) if (!f[i]) rest++;
if (rest+idx <= res) return;
if (idx==K) {
res = cur;
memcpy(g, h, sizeof(h));
return;
}
// do not put
solve(idx+1, cur);
// put
if (!f[idx]) {
bool tmp[300];
memcpy(tmp, f, sizeof(f));
FORIT(ito, vg[idx]) {
f[*ito] = true;
}
h[idx] = true;
solve(idx+1, cur+1);
// revert
memcpy(f, tmp, sizeof(f));
h[idx] = false;
}
}
void find_maximal() {
int cur=0;
REP(i, 300) {
int idx = rand()%K;
if (!f[idx]) {
FORIT(ito, vg[idx]) {
f[*ito] = true;
}
f[idx] = true;
h[idx] = true;
cur++;
}
}
if (cur > res) {
res = cur;
memcpy(g, h, sizeof(g));
}
}
int main() {
// memoize 2 lines
while (cin >> N >> M) {
if (N<=2 || M<=2) {
// no solution
puts("0");
REP(i, N) {
REP(j, M) printf(".");
puts("");
}
continue;
}
if (N==8 && M==9) {
cout<<12<<endl;
cout<<"AAA.BBB.C\n.ADDDBCCC\nEA.DFB.GC\nEEEDFFFG.\nEHHHFIGGG\n.JH.KIIIL\n.JH.KILLL\nJJJKKK..L\n";
continue;
}
if (N==9 && M==9) {
cout<<13<<endl;
cout<<"A.BBBCDDD\nAAAB.C.D.\nAE.BCCCDF\n.EEEGHFFF\n.EGGGHHHF\nIII.GHJJJ\n.IKLLLMJ.\n.IK.L.MJ.\n.KKKLMMM.\n";
continue;
}
if (N==9 && M==8) {
cout<<12<<endl;
cout<<"AAA.BCCC\n.ABBBDC.\n.A.EBDC.\nFEEEDDDG\nFFFEHGGG\nFIIIHHHG\n.JIKHLLL\n.JIKKKL.\nJJJK..L.\n";
continue;
}
K=4*(N-2)*(M-2);
vg = vector<V>(K);
REP(y1, N-2) REP(x1, M-2) REP(r1, 4) {
REP(y2, N-2) REP(x2, M-2) REP(r2, 4) {
bool col = false;
REP(u1, 5) REP(u2, 5) {
int ay1=y1+dip[r1][u1][0];
int ax1=x1+dip[r1][u1][1];
int ay2=y2+dip[r2][u2][0];
int ax2=x2+dip[r2][u2][1];
if (ay1==ay2 && ax1==ax2) {
col = true;
}
}
if (col) {
vg[code(y1, x1, r1)].push_back(code(y2, x2, r2));
}
}
}
REP(y, N-2) REP(x, M-2) REP(r1, 4) REP(r2, 4) if (r1 != r2) {
vg[code(y, x, r1)].push_back(code(y, x, r2));
}
// solve(0, 0);
res=0;
MEMSET(g, false);
REP(itr, 50000) {
MEMSET(f, false);
MEMSET(h, false);
find_maximal();
}
printf("%d\n", res);
// print
vector<string> res(N, string(M, '.'));
int z=0;
REP(i, K) if (g[i]) {
int x=i/4%(M-2), y=i/4/(M-2), r=i%4;
REP(u, 5) {
res[y+dip[r][u][0]][x+dip[r][u][1]] = 'A'+z;
}
z++;
}
/*
REP(i, N) cout<<res[i]<<"\\n";
cout<<endl;
*/
REP(i, N) cout<<res[i]<<endl;
}
}
接下来看一下black_horse2014的思路及代码:
思路:状态压缩动态规划,令\(f[i][mask]\)表示:到了第\(i\)行时,上面两行的状态为\(mask\)时的最多方案数。
那么状态转移方程时很显然的,我们在开一个数组记录一下当前行的选择,就可以很容易地转换出最终的方案。
虽然说口胡很简单,但是代码实现还是非常难的,需要对位运算以及状态压缩DP有很深刻的掌握。
下面是代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef pair<int, LL> PIL;
typedef pair<LL, int> PLI;
typedef vector<int> VI;
typedef vector<PII> VPII;
typedef double DB;
#define pb push_back
#define mset(a, b) memset(a, b, sizeof a)
#define all(x) (x).begin(), (x).end()
#define bit(x) (1 << (x))
#define bitl(x) (1LL << (x))
#define sqr(x) ((x) * (x))
#define sz(x) ((int)(x.size()))
#define cnti(x) (__builtin_popcount(x))
#define cntl(x) (__builtin_popcountll(x))
#define clzi(x) (__builtin_clz(x))
#define clzl(x) (__builtin_clzll(x))
#define ctzi(x) (__builtin_ctz(x))
#define ctzl(x) (__builtin_ctzll(x))
#define X first
#define Y second
#define Error(x) cout << #x << " = " << x << endl
template <typename T, typename U>
inline void chkmax(T& x, U y) {
if (x < y) x = y;
}
template <typename T, typename U>
inline void chkmin(T& x, U y) {
if (y < x) x = y;
}
int n, m;
int dp[10][bit(18)];
int f[10][bit(18)];
int g[10][bit(18)];
const int dx[][5] = {{0, 0, 0, 1, 2}, {0, 1, 1, 1, 2}, {0, 1, 2, 2, 2}, {0, 1, 1, 1, 2}};
const int dy[][5] = {{0, 1, 2, 1, 1}, {2, 0, 1, 2, 2}, {1, 1, 0, 1, 2}, {0, 0, 1, 2, 0}};
bool out(int x, int y) {
return x > n || y >= m || y < 0;
}
int S;
char s[10][10];
void go(int r, int state, int nstate, int pos, long long add, int cnt) {
if (pos == m) {
if(dp[r][nstate] < cnt) {
dp[r][nstate] = cnt;
f[r][nstate] = add;
g[r][nstate] = S;
}
return;
}
go(r, state, nstate, pos + 1, add, cnt);
int x = r, y = pos;
for (int i = 0; i < 4; i++) {
bool flg = 1;
for (int j = 0; flg && j < 5; j++) {
int nx = x + dx[i][j], ny = y + dy[i][j];
if (out(nx, ny)) {
flg = 0;
break;
}
if (nx <= r + 1) {
if (state >> ((nx - r) * m + ny) & 1) {
flg = 0;
break;
}
} else {
if (nstate >> (m + ny) & 1) {
flg = 0;
break;
}
}
}
if (!flg) continue;
int cstate = state, cnstate = nstate, cadd = add | bitl(pos*4+i);
for (int j = 0; flg && j < 5; j++) {
int nx = x + dx[i][j], ny = y + dy[i][j];
if (nx <= r + 1) {
cstate |= bit((nx-r)*m+ny);
if (nx == r + 1) {
cnstate |= bit(ny);
}
} else {
cnstate |= bit(ny + m);
}
}
go(r, cstate, cnstate, pos + 1, cadd, cnt + 1);
}
}
int main() {
scanf("%d%d", &n, &m);
if (n <= 2 || m <= 2) {
puts("0");
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) putchar('.');
puts("");
}
return 0;
}
memset(dp, -1, sizeof dp);
dp[0][0] = 0;
for (int i = 1; i <= n-2; i++) {
for (int j = 0; j < bit(2*m); j++) if (~dp[i-1][j]) {
S = j;
go(i, j, j >> m, 0, 0, dp[i-1][j]);
}
}
int ans = 0, opt = 0;
for (int j = 0; j < bit(2*m); j++) {
if (dp[n-2][j] > ans) {
ans = dp[n-2][j];
opt = j;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j < m; j++) s[i][j] = '.';
s[i][m] = 0;
}
int r = n-2;
int tot = ans;
cout << ans << endl;
while (r > 0) {
long long st = f[r][opt];
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < 4; j++) {
if (st >> (4*i+j) & 1) {
int x = r, y = i;
for (int k = 0; k < 5; k++) {
int nx = x + dx[j][k], ny = y + dy[j][k];
s[nx][ny] = 'A' + tot - 1;
}
tot--;
}
}
}
opt = g[r][opt], r--;
}
for (int i = 1; i <= n; i++) {
puts(s[i]);
}
return 0;
}
接下来是coder的:
思路:对于一些打表我已经无力去吐槽了他的代码,我们可以直接砍掉\(\frac{2}{3}\)。思路十分简单,暴力dfs,并且将最后剩下的一点直接打表处理最优,然后利用这一个剪枝,所以,就直接看代码啦(只需要看go和main函数的)。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <map>
#include <cstring>
typedef long long ll;
const int inf = 1000000009;
const double pi = acos(-1.0);
using namespace std;
int i, j, k, m, n, cnt, e = -1;
char ans[10][10], cur[10][10];
signed char d[10][10][1<<9][1<<9];
string z = "AAA.BCCC..ABBB.CD..AE.BFCD.EEEFFFDDDG.E.HFIIIGGGJHHHI.GK.JHL.IM.KJJJLMMMKKK.LLL.M";
inline void setit(int a, int b, int k, int& x, int& y) {
if (b & (1<<k)) {
x = a | (1<<k);
y = b ^ (1<<k);
} else {
if (a & (1<<k)) {
x = a ^ (1<<k);
} else x = a;
y = b;
}
}
signed char solve(int x, int y, int m1, int m2) {
if (y >= n) return solve(x+1, 0, m1, m2);
if (x >= m) {
return 0;
}
signed char& ret = d[x][y][m1][m2];
if (ret != -1) return ret;
ret = 0;
// skip
int t1, t2;
setit(m1, m2, y, t1, t2);
ret = solve(x, y+1, t1, t2);
if (y + 3 <= n) {
if ( (m1 & (1<<y)) || (m1 & (1<<(y+1))) || (m1 & (1<<(y+2))) || (m2 & (1<<(y+1))));
else {
setit(m1, m2, y, t1, t2);
setit(t1, t2, y+1, t1, t2);
t2 |= (1<<(y+1));
t1 |= (1<<(y+1));
t1 |= (1<<(y+2));
if (solve(x, y+2, t1, t2) + 1 > ret) ret = solve(x, y+2, t1, t2) + 1;
}
if ( (m2 & (1<<y)) || (m2 & (1<<(y+1))) || (m2 & (1<<(y+2))) || (m1 & (1<<(y+2))));
else {
setit(m1, m2, y, t1, t2);
setit(t1, t2, y+1, t1, t2);
setit(t1, t2, y+2, t1, t2);
t2 |= (1<<(y+2));
t1 |= (1<<(y+1));
t1 |= (1<<(y));
t1 |= (1<<(y+2));
if (solve(x, y+3, t1, t2) + 1 > ret) ret = solve(x, y+3, t1, t2) + 1;
}
if ((m1 & (1<<(y+1))) || (m2 & (1<<(y+1))));
else {
setit(m1, m2, y, t1, t2);
setit(t1, t2, y+1, t1, t2);
setit(t1, t2, y+2, t1, t2);
t2 |= (1<<(y+1));
t2 |= (1<<(y));
t2 |= (1<<(y+2));
t1 |= (1<<(y+1));
if (solve(x, y+3, t1, t2) + 1 > ret) ret = solve(x, y+3, t1, t2) + 1;
}
if ( (m2 & (1<<y)) || (m2 & (1<<(y+1))) || (m2 & (1<<(y+2))) || (m1 & (1<<(y))));
else {
setit(m1, m2, y, t1, t2);
setit(t1, t2, y+1, t1, t2);
setit(t1, t2, y+2, t1, t2);
t2 |= (1<<(y));
t1 |= (1<<(y+1));
t1 |= (1<<(y));
t1 |= (1<<(y+2));
if (solve(x, y+3, t1, t2) + 1 > ret) ret = solve(x, y+3, t1, t2) + 1;
}
}
return ret;
}
void rec(int x, int y, int m1, int m2, int ret) {
if (y >= n) {
rec(x+1, 0, m1, m2, ret);
return;
}
if (x >= m) {
return;
}
// skip
int t1, t2;
setit(m1, m2, y, t1, t2);
if (ret == solve(x, y+1, t1, t2)) {
rec(x, y+1, t1, t2, ret);
return;
}
if (y + 3 <= n) {
if ( (m1 & (1<<y)) || (m1 & (1<<(y+1))) || (m1 & (1<<(y+2))) || (m2 & (1<<(y+1))));
else {
setit(m1, m2, y, t1, t2);
setit(t1, t2, y+1, t1, t2);
setit(t1, t2, y+2, t1, t2);
t2 |= (1<<(y+1));
t1 |= (1<<(y+1));
if (solve(x, y+3, t1, t2) + 1 == ret) {
rec(x, y+3, t1, t2, ret-1);
ans[x-2][y]=ans[x-2][y+1]=ans[x-2][y+2] = ans[x-1][y+1] = ans[x][y+1] = ret + 'A' - 1;
return;
}
}
if ( (m2 & (1<<y)) || (m2 & (1<<(y+1))) || (m2 & (1<<(y+2))) || (m1 & (1<<(y+2))));
else {
setit(m1, m2, y, t1, t2);
setit(t1, t2, y+1, t1, t2);
setit(t1, t2, y+2, t1, t2);
t2 |= (1<<(y+2));
t1 |= (1<<(y+1));
t1 |= (1<<(y));
t1 |= (1<<(y+2));
if (solve(x, y+3, t1, t2) + 1 == ret) {
rec(x, y+3, t1, t2, ret-1);
ans[x-2][y+2]=ans[x-1][y]=ans[x-1][y+1] = ans[x-1][y+2] = ans[x][y+2] = ret + 'A' - 1;
return;
}
}
if ((m1 & (1<<(y+1))) || (m2 & (1<<(y+1))));
else {
setit(m1, m2, y, t1, t2);
setit(t1, t2, y+1, t1, t2);
setit(t1, t2, y+2, t1, t2);
t2 |= (1<<(y+1));
t2 |= (1<<(y));
t2 |= (1<<(y+2));
t1 |= (1<<(y+1));
if (solve(x, y+3, t1, t2) + 1 == ret) {
rec(x, y+3, t1, t2, ret-1);
ans[x-2][y+1]=ans[x-1][y+1]=ans[x][y] = ans[x][y+1] = ans[x][y+2] = ret + 'A' - 1;
return;
}
}
if ( (m2 & (1<<y)) || (m2 & (1<<(y+1))) || (m2 & (1<<(y+2))) || (m1 & (1<<(y))));
else {
setit(m1, m2, y, t1, t2);
setit(t1, t2, y+1, t1, t2);
setit(t1, t2, y+2, t1, t2);
t2 |= (1<<(y));
t1 |= (1<<(y+1));
t1 |= (1<<(y));
t1 |= (1<<(y+2));
if (solve(x, y+3, t1, t2) + 1 == ret) {
rec(x, y+3, t1, t2, ret-1);
ans[x-2][y]=ans[x-1][y]=ans[x-1][y+1] = ans[x-1][y+2] = ans[x][y] = ret + 'A' - 1;
return;
}
}
}
throw 9;
}
const string H[3]={"###..#.#.#..",".#.###.#.###",".#...#####.."};
int best = 0;
void go(int x, int y, int c) {
if (c > best) {
best = c;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
ans[i][j] = cur[i][j];
}
if (x + 3 > m) {
return;
}
if (y + 3 > n) {
go(x+1, 0, c);
return;
}
for (int k = 0; k < 4; k++) {
int f = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (H[i][k*3+j] == '#' && cur[x+i][y+j] != 0) f = 1;
if (f) continue;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (H[i][k*3+j] == '#') cur[x+i][y+j] = c + 'A';
go(x, y+1, c+1);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (H[i][k*3+j] == '#') cur[x+i][y+j] = 0;
}
if (y == 0 && m - x <= 6) {
int t= 0;
if (m - x == 6) t = 8;
else if (m -x == 5) t = 7;
else if (m-x == 4) t = 5;
else if (m-x == 3) t = 4;
if (t + c <= best) return;
}
go(x, y+1, c);
}
int main()
{
cin >> m >> n;
if (m == 9 && n == 9) {
cout << 13 << endl;
for (i = 0; i < 9; i++) {
for (j = 0; j < 9; j++) {
cout << z[9*i+j];
}
cout << endl;
}
return 0;
}
/* if (m >= 3 && n >= 3) {
memset(d, -1, sizeof(d));
cnt = solve(2, 0, 0, 0);
cout << cnt << endl;
rec(2, 0, 0, 0, cnt);
} else {
cout << 0 << endl;
}*/
go(0, 0, 0);
cout << best << endl;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
if (ans[i][j] == 0) ans[i][j] = '.';
for (i = 0; i < m; i++)
puts(ans[i]);
return 0;
}
最后一个Kostroma的,真的是,悲惨。
思路:暴力dfs+一个用途不大的剪枝,然后就T飞了。
他的代码是暴力处理出了所有的T情况,这个代码量就……
先看一下最原始的代码:
TLE on test 76
//#pragma comment(linker, "/STACK:64000000")
#pragma hdrstop
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <math.h>
#include <vector>
#include <set>
using namespace std;
/*
BE CAREFUL: ISN'T INT EQUAL TO LONG LONG?
REAL SOLUTION AFTER MAIN FUNCTION
*/
#define mp make_pair
#define pb push_back
typedef long long li;
typedef long double ld;
typedef pair <int, int> pi;
void solve();
int main ()
{
#ifdef _DEBUG
freopen ("in.txt", "r", stdin);
#endif
int t=1;
//cout<<t<<endl;
while (t--)
solve();
return 0;
}
//#define int li
int n, m;
char a[10][10];
char answer[10][10];
vector < pi > need;
int ans=0;
bool modify1 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x, y+1));
need.pb (mp(x, y+2));
need.pb (mp(x+1, y+1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo1 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x, y+1));
need.pb (mp(x, y+2));
need.pb (mp(x+1, y+1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
bool modify2 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y+1));
need.pb (mp(x+1, y+2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo2 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y+1));
need.pb (mp(x+1, y+2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
bool modify3 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y-1));
need.pb (mp(x+1, y-2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo3 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y-1));
need.pb (mp(x+1, y-2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
bool modify4 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+2, y));
need.pb (mp(x+2, y-1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo4 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+2, y));
need.pb (mp(x+2, y-1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
void rec ( char c, int x, int y, int done=0 )
{
bool all=true;
for (int i=x; i<n && i<x+3; i++)
for ( int j=((i==x)?y:0); j<m; j++ )
{
if ( ans*5+done>n*m+4 )
return;
if (a[i][j]==1)
done++;
else
continue;
if (modify1 (c, i, j))
{
all=false;
rec(c+1, i, j+1, done-1);
undo1 (c, i, j);
}
if (modify2 (c, i, j))
{
all=false;
rec (c+1, i, j+1, done-1);
undo2 (c, i, j);
}
if (modify3 (c, i, j))
{
all=false;
rec (c+1, i, j+1, done-1);
undo3 (c, i, j);
}
if (modify4 (c, i, j))
{
all=false;
rec (c+1, i, j+1, done-1);
undo4 (c, i, j);
}
}
if (all)
{
if (c-'A'>ans)
{
ans=c-'A';
for (int i=0; i<n; i++)
for (int j=0; j<m; j++)
answer[i][j]=a[i][j];
}
}
}
void solve ()
{
cin>>n>>m;
for (int i=0; i<n; i++)
for (int j=0; j<m; j++)
a[i][j]=answer[i][j]=1;
rec ('A', 0, 0);
cout<<ans<<endl;
for (int i=0; i<n; i++)
{
for (int j=0; j<m; j++)
if (answer[i][j]==1)
cout<<".";
else
cout<<answer[i][j];
cout<<endl;
}
}
十分好理解。
为了避免再次T掉,Kostroma加上了一些表,然后没有用地跑到了第79个点。
TLE on test 79
//#pragma comment(linker, "/STACK:64000000")
#pragma hdrstop
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <math.h>
#include <vector>
#include <set>
using namespace std;
/*
BE CAREFUL: ISN'T INT EQUAL TO LONG LONG?
REAL SOLUTION AFTER MAIN FUNCTION
*/
#define mp make_pair
#define pb push_back
typedef long long li;
typedef long double ld;
typedef pair <int, int> pi;
void solve();
int main ()
{
#ifdef _DEBUG
freopen ("in.txt", "r", stdin);
#endif
int t=1;
//cout<<t<<endl;
while (t--)
solve();
return 0;
}
//#define int li
int n, m;
char a[10][10];
char answer[10][10];
vector < pi > need;
int ans=0;
bool modify1 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x, y+1));
need.pb (mp(x, y+2));
need.pb (mp(x+1, y+1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo1 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x, y+1));
need.pb (mp(x, y+2));
need.pb (mp(x+1, y+1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
bool modify2 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y+1));
need.pb (mp(x+1, y+2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo2 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y+1));
need.pb (mp(x+1, y+2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
bool modify3 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y-1));
need.pb (mp(x+1, y-2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo3 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y-1));
need.pb (mp(x+1, y-2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
bool modify4 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+2, y));
need.pb (mp(x+2, y-1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo4 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+2, y));
need.pb (mp(x+2, y-1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
void rec ( char c, int x, int y, int done=0 )
{
bool all=true;
for (int i=x; i<n && i<x+3; i++)
for ( int j=((i==x)?y:0); j<m; j++ )
{
if ( ans*5+done>n*m+3 || done>16)
return;
if (a[i][j]==1)
done++;
else
continue;
if (modify1 (c, i, j))
{
all=false;
rec(c+1, i, j+1, done-1);
undo1 (c, i, j);
}
if (modify2 (c, i, j))
{
all=false;
rec (c+1, i, j+1, done-1);
undo2 (c, i, j);
}
if (modify3 (c, i, j))
{
all=false;
rec (c+1, i, j+1, done-1);
undo3 (c, i, j);
}
if (modify4 (c, i, j))
{
all=false;
rec (c+1, i, j+1, done-1);
undo4 (c, i, j);
}
}
if (all)
{
if (c-'A'>ans)
{
ans=c-'A';
for (int i=0; i<n; i++)
for (int j=0; j<m; j++)
answer[i][j]=a[i][j];
}
}
}
void solve ()
{
cin>>n>>m;
for (int i=0; i<n; i++)
for (int j=0; j<m; j++)
a[i][j]=answer[i][j]=1;
if (n==7 && m==9)
{
cout<<"10\nAAAB..CCC\n.ADBBB.C.\n.ADBEEECF\nGDDD.EFFF\nGGGHIE.JF\nGHHHIIIJ.\n...HI.JJJ";
return;
}
if (n==9 && m==7)
{
cout<<"10\nAAABBB.\n.A..BC.\nDA.EBC.\nDDDECCC\nDFEEE.G\n.FFFGGG\nHFIIIJG\nHHHI.J.\nH..IJJJ";
return;
}
if (n==8 && m==8)
{
cout<<"10\nAAABBBC.\n.A..B.C.\nDA..BCCC\nDDDEEE.F\nDGGGEFFF\n.HGIE.JF\n.HGIIIJ.\nHHHI.JJJ";
return;
}
rec ('A', 0, 0);
cout<<ans<<endl;
for (int i=0; i<n; i++)
{
for (int j=0; j<m; j++)
if (answer[i][j]==1)
cout<<".";
else
cout<<answer[i][j];
cout<<endl;
}
}
最后,他又加上了两个表,然后很华丽地T81。
TLE on test 81
//#pragma comment(linker, "/STACK:64000000")
#pragma hdrstop
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <math.h>
#include <vector>
#include <set>
using namespace std;
/*
BE CAREFUL: ISN'T INT EQUAL TO LONG LONG?
REAL SOLUTION AFTER MAIN FUNCTION
*/
#define mp make_pair
#define pb push_back
typedef long long li;
typedef long double ld;
typedef pair <int, int> pi;
void solve();
int main ()
{
#ifdef _DEBUG
freopen ("in.txt", "r", stdin);
#endif
int t=1;
//cout<<t<<endl;
while (t--)
solve();
return 0;
}
//#define int li
int n, m;
char a[10][10];
char answer[10][10];
vector < pi > need;
int ans=0;
bool modify1 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x, y+1));
need.pb (mp(x, y+2));
need.pb (mp(x+1, y+1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo1 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x, y+1));
need.pb (mp(x, y+2));
need.pb (mp(x+1, y+1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
bool modify2 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y+1));
need.pb (mp(x+1, y+2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo2 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y+1));
need.pb (mp(x+1, y+2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
bool modify3 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y-1));
need.pb (mp(x+1, y-2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo3 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+1, y-1));
need.pb (mp(x+1, y-2));
need.pb (mp(x+2, y));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
bool modify4 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+2, y));
need.pb (mp(x+2, y-1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
if ( need[i].first<0 || need[i].first>=n || need[i].second<0 || need[i].second>=m || a[need[i].first][need[i].second]!=1 )
return false;
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=c;
return true;
}
void undo4 (char c, int x, int y)
{
need.resize(0);
need.pb (mp(x, y));
need.pb (mp(x+1, y));
need.pb (mp(x+2, y));
need.pb (mp(x+2, y-1));
need.pb (mp(x+2, y+1));
for (int i=0; i<need.size(); i++)
a[need[i].first][need[i].second]=1;
}
void rec ( char c, int x, int y, int done=0 )
{
bool all=true;
for (int i=x; i<n && i<x+3; i++)
for ( int j=((i==x)?y:0); j<m; j++ )
{
if ( ans*5+done>n*m+3 || done>16)
return;
if (a[i][j]==1)
done++;
else
continue;
if (modify1 (c, i, j))
{
all=false;
rec(c+1, i, j+1, done-1);
undo1 (c, i, j);
}
if (modify2 (c, i, j))
{
all=false;
rec (c+1, i, j+1, done-1);
undo2 (c, i, j);
}
if (modify3 (c, i, j))
{
all=false;
rec (c+1, i, j+1, done-1);
undo3 (c, i, j);
}
if (modify4 (c, i, j))
{
all=false;
rec (c+1, i, j+1, done-1);
undo4 (c, i, j);
}
}
if (all)
{
if (c-'A'>ans)
{
ans=c-'A';
for (int i=0; i<n; i++)
for (int j=0; j<m; j++)
answer[i][j]=a[i][j];
}
}
}
void solve ()
{
cin>>n>>m;
for (int i=0; i<n; i++)
for (int j=0; j<m; j++)
a[i][j]=answer[i][j]=1;
if (n==7 && m==9)
{
cout<<"10\nAAAB..CCC\n.ADBBB.C.\n.ADBEEECF\nGDDD.EFFF\nGGGHIE.JF\nGHHHIIIJ.\n...HI.JJJ";
return;
}
if (n==9 && m==7)
{
cout<<"10\nAAABBB.\n.A..BC.\nDA.EBC.\nDDDECCC\nDFEEE.G\n.FFFGGG\nHFIIIJG\nHHHI.J.\nH..IJJJ";
return;
}
if (n==8 && m==8)
{
cout<<"10\nAAABBBC.\n.A..B.C.\nDA..BCCC\nDDDEEE.F\nDGGGEFFF\n.HGIE.JF\n.HGIIIJ.\nHHHI.JJJ";
return;
}
if (n==8 && m==9)
{
cout<<"12\nA.BBBC...\nAAABDCCCE\nA.FBDCEEE\nFFFDDDG.E\nH.FIIIGGG\nHHHJIKG.L\nHJJJIKLLL\n...JKKK.L";
return;
}
if (n==9 && m==8)
{
cout<<"12\nAAABBB.C\n.AD.BCCC\n.AD.B.EC\nFDDDEEE.\nFFFGGGEH\nFIIIGHHH\n.JIKG.LH\n.JIKKKL.\nJJJK.LLL";
return;
}
rec ('A', 0, 0);
cout<<ans<<endl;
for (int i=0; i<n; i++)
{
for (int j=0; j<m; j++)
if (answer[i][j]==1)
cout<<".";
else
cout<<answer[i][j];
cout<<endl;
}
}
如果给他的代码手动加上一个\(9\times 9\)的情况就能AC了呢。