DFS暴力剪枝2014广州网络赛的J题,
太恶心了,大模拟,狂搜索
Orz...............
注意最优化剪枝。
对于一个点,搜索时(此点必定是直线的起点,否则会数重的),先判断水平和竖直能不能划线(注意不要数重,当i==1 || j==1时才能竖直水平化);在枚举在此点下面的点,合法性剪枝,点数要大于3.
狠黄狠暴力。
输入输出优化 + G++交的,982ms
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define inf 1000000000
using namespace std;
typedef long long ll;
void in(int &x){
char ch; int minus = 0;
while (ch=getchar(), (ch<'0'||ch>'9') && ch!='-');
if (ch == '-') minus = 1, x = 0;
else x = ch-'0';
while (ch=getchar(), ch>='0'&&ch<='9') x = x*10+ch-'0';
if (minus) x = -x;
}
void in(ll &x){
char ch; int minus = 0;
while (ch=getchar(), (ch<'0'||ch>'9') && ch!='-');
if (ch == '-') minus = 1, x = 0;
else x = ch-'0';
while (ch=getchar(), ch>='0'&&ch<='9') x = x*10+ch-'0';
if (minus) x = -x;
}
void out(int x){
char hc[30];int len, minus=0;
if (x<0) minus = 1, x = -x;
len = 0; hc[len++] = x%10+'0';
while (x/=10) hc[len++] = x%10+'0';
if (minus) putchar('-');
for (int i=len-1; i>=0; i--) putchar(hc[i]);
}
void out(ll x){
char hc[30];int len, minus=0;
if (x<0) minus = 1, x = -x;
len = 0; hc[len++] = x%10+'0';
while (x/=10) hc[len++] = x%10+'0';
if (minus) putchar('-');
for (int i=len-1; i>=0; i--) putchar(hc[i]);
}
const int N = 50+10;
int a[N][N];
int n,m;
int sum;
int ans;
int isin(int x,int y)
{
if(x>=1 && x<=n && y>=1 && y<=m) return 1;
return 0;
}
void dfs(int now,int re)
{
if(now>=ans) return ;
if(re==0)
{
//printf("geng xi %d\n",now);
ans = min(ans,now);
return ;
}
int cnt = 0;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cnt = max(cnt,a[i][j]);
if(now + cnt >=ans) return ;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j])
{
int fl=1,fll=1;
if(i==1){
for(int k=1;k<=n;k++) if(!a[k][j]) {fl=0;break;}
if(fl)
{
for(int k=1;k<=n;k++) a[k][j]--;
dfs(now+1,re-n);
for(int k=1;k<=n;k++) a[k][j]++;
}
}
if(j==1){
for(int k=1;k<=m;k++) if(!a[i][k]) {fll=0;break;}
if(fll)
{
for(int k=1;k<=m;k++) a[i][k]--;
dfs(now+1,re-m);
for(int k=1;k<=m;k++) a[i][k]++;
}
}
for(int ii=i+1;ii<=n;ii++)
{
for(int jj=1;jj<=m;jj++)
{
if(!a[i][j]) break;
if(!a[ii][jj]) continue;
if(ii==i || jj==j) continue;
int dx = ii-i,dy=jj-j;
int tx=i,ty=j;
int cn=0,flag=1;
while(1)
{
if(!isin(tx,ty)) break;
if(!a[tx][ty]) {flag=0;break;}
cn++;
tx+=dx;
ty+=dy;
}
tx=i-dx,ty=j-dy;
if(isin(tx,ty)) flag=0;
if(flag==0) continue;
if(cn<3) continue;
tx=i,ty=j;
while(1)
{
if(!isin(tx,ty)) break;
a[tx][ty]--;
tx+=dx;
ty+=dy;
}
//printf("直线 %d,%d --- %d,%d cut = %d , now = %d ,re = %d\n",i,j,ii,jj,cn,now+1,re-cn);
dfs(now+1,re-cn);
tx=i,ty=j;
while(1)
{
if(!isin(tx,ty)) break;
a[tx][ty]++;
tx+=dx;
ty+=dy;
}
}
}
return ;
}
}
}
}
int main()
{
int t;
in(t);
while(t--)
{
sum=0;
ans = inf;
in(n);in(m);
n++;m++;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
in(a[i][j]);
sum+=a[i][j];
}
ans = min(14,sum/3);
dfs(0,sum);
out(ans);
putchar('\n');
}
return 0;
}
本文介绍了一种使用深度优先搜索(DFS)结合剪枝策略解决特定问题的方法。该问题来源于2014年广州网络赛J题,通过优化搜索过程避免无效计算,实现了高效的求解方案。
392

被折叠的 条评论
为什么被折叠?



