您的位置:首页 > 其它

HDU 5031:看脸的DFS

2014-09-22 11:20 309 查看
我仍然觉得这道题十分的不科学……

题目是说你有一个坐标系中的点阵,其中点的两个坐标范围分别为0~n和0~m,而且都是整数点。你的好基友在这坐标系上画了几条直线,每条直线保证只穿过整数点,而且至少穿过3个整数点。现在你得到了一个矩阵,矩阵描述了每个点都被穿过了多少次,你需要确定你的基友最少画了多少条直线。答案保证不超过14.

这真没什么好办法,只能搜索,但是如果真老老实实地搜,肯定会T到死……

既然要搜索,我们肯定要找到这里所有的直线,不妨先看看怎样不重不漏地找出这里所有的直线吧,我的算法是这样的:先预处理出所有不是0的点,从左向右,从上向下扫描每个点,以它为起点,然后从它开始继续从左向右,从上到下枚举每个点作为终点,如果这两个点确定的向量的两个分量不互质(例如(1,1)和(3,3)向量是(2,2)),那么肯定没戏,他们中间一定隔过了一个点,或者中间的点是0;设这个向量为vec;

然后从起点开始每次减去vec枚举,看到0就说明没戏,看到不为0的点也说明没戏,因为我是从左向右,从上到下扫描的,假如我看到一个在我上面的(或左边的)点,那么应该是这个点来找我才对,这说明这条直线已经被找过了,所以不要;

接下来从终点每次加上vec枚举,看到0说明没戏,而且要注意记录一下是否看到了至少一个1,如果是的话就ok,这就是一条满足要求的直线了。

然后说搜索,我最后AC时采用的搜索姿势是:

(1)找线的工作放在每层搜索之前做,这很重要,因为你会发现找到一条直线并划去这条直线之后,下一层的合法直线数会急剧下降,这对于这道题来说非常重要,如果你一开始就找出了所有直线,维护他们是否合法的代价就太大了,还不如每次都现找;

(2)找出所有直线后按照他们覆盖点的个数排序,当前层选取直线的时候从大到小选取,并且只取最大的5条(如果合法直线比5条多的话)。然后,第一次找到一个解,就认为这个解是最优解并退出。

这个真的是看脸,我至今都觉得这个算法不科学,只能说他对的概率不小就是了,但是拿这个算法AC简直糊我一脸……

不评论了,这个看脸的社会……

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;

const int INF=1<<30;
int n,m,t;

struct Point
{
int x,y;
Point(){}
Point(int _x, int _y)
{
x=_x;
y=_y;
}
void set(int _x, int _y)
{
x=_x;
y=_y;
}
Point operator + (const Point &b) const
{
return Point(x+b.x, y+b.y);
}
Point operator - (const Point &b) const
{
return Point(x-b.x, y-b.y);
}
int operator ^(const Point &b) const
{
return x*b.y - y*b.x;
}
};

struct Line
{
Point s,e;
int cover;
Line(){}
void set(Point _s, Point _e, int _c)
{
s=_s;
e=_e;
cover=_c;
}

bool operator < (const Line &b)
{
return cover < b.cover;
}
};

Point point[5000];
int p_point = 0;

int map[70][70];
int min_ans = 14;
bool found = false;

void init()
{
p_point=0;
memset(map, 0, sizeof(map));
min_ans = 14;
found = false;
return;
}

int gcd(int x, int y)
{
if(x<y)
swap(x,y);
if(y==0)
return x;
if(x%y==0)
return y;
return gcd(y, x%y);
}

bool valid(Point p)
{
return p.x >=0 && p.y >= 0 && p.x <=n && p.y <=m;
}

bool CheckLine(int p1, int p2, int &cover)//判断p1 p2组成的直线是否合法,顺便算出他们的覆盖点数
{
Point now_vec = point[p2] - point[p1];
if(gcd( abs(now_vec.x), abs(now_vec.y)) != 1)
return false;

int now_cover = 0;
Point tmp = point[p1];
tmp = tmp - now_vec;
while(valid(tmp))
{
if(map[tmp.x][tmp.y] == 0)
return false;
else if(tmp.x <= point[p1].x)
return false;

now_cover ++;
tmp = tmp - now_vec;
}

tmp = point[p2];
tmp = tmp + now_vec;
bool found_one = false;
while(valid(tmp))
{
found_one = true;
if(map[tmp.x][tmp.y] == 0)
return false;
now_cover++;
tmp = tmp + now_vec;
}
if(!found_one)
return false;

cover = now_cover;
return true;
}

void DetermineLines(Line line[], int &p_line)
{
int i,j;
for(i=1; i<=p_point -1;i++)
{
if(map[point[i].x][point[i].y] ==0)
continue;
for(j=i+1; j<=p_point; j++)
{
if(map[point[j].x][point[j].y]==0)
continue;
int cover;
if( CheckLine(i,j, cover) )
{
line[++p_line].set(point[i], point[j], cover);
}
}
}
return;
}

void drop(Line l)
{
Point p1 = l.s, p2 = l.e;

Point now_vec = p2 - p1;
Point tmp = p1;

while(valid(tmp))
{
map[tmp.x][tmp.y] --;
tmp = tmp - now_vec;
}

tmp = p2;
while(valid(tmp))
{
map[tmp.x][tmp.y] --;
tmp = tmp + now_vec;
}
return ;
}

void resume(Line l)
{
Point p1 = l.s, p2 = l.e;

Point now_vec = p2 - p1;
Point tmp = p1;
while(valid(tmp))
{
map[tmp.x][tmp.y]++;
tmp = tmp - now_vec;
}

tmp = p2;
while(valid(tmp))
{
map[tmp.x][tmp.y]++;
tmp = tmp + now_vec;
}
return ;
}

bool cmp(const Line &a, const Line &b)
{
return a.cover > b.cover;
}

bool check()
{
int i;
for(i=1; i<=p_point; i++)
{
if(map[point[i].x][point[i].y] != 0)
return false;
}
return true;
}

void DFS(int depth)
{
Line line[3000];
int p_line = 0;

DetermineLines(line, p_line);
sort(line+1, line + p_line +1, cmp);

if(check())
{
min_ans = depth-1;
found = true;
return ;
}

if(depth > min_ans)
return;

int i;

for(i=1; i<=min(p_line,4);i++)
{
drop(line[i]);

DFS(depth+1);
if(found)
break;

resume(line[i]);
}
return ;
}

int main()
{
scanf("%d", &t);
int files;
for(files=1; files<=t; files++)
{
init();
scanf("%d %d", &n, &m);
int i,j;
for(i=0; i<=n; i++)
{
for(j=0; j<=m; j++)
{
scanf("%d", &map[i][j]);
if(map[i][j]!=0)
{
point[++p_point].set(i,j);
}
}
}

DFS(1);
printf("%d\n", min_ans);

}

//system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: