ACM的题 中大soj 1353

alfredtofu 2011-01-28 12:07:16
题目:http://soj.me/1353
我是这样想的,题目说不能脚印不能重复,假设走了n个点,每两个点构成一条线段,就是这所有的线段都不能有交点,除了顶点可以相交,此外对于角度也有要求,这是我对题目的理解,不知道有没有错,不过提交总是WA,不知道为什么,代码如下,求指点,我纠结了很久,谢谢:

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
using namespace std;

struct node {
int x;
int y;
}data[1001];

int _max = 1;
bool isVis[1001];
int n;
int order[1001]; //存放已经访问的点,按访问顺序存放


//判断旋转角度是否小于等于180度
bool angle_can(int p1, int p2, int p3) {
if(data[p2].x == data[p3].x) {
if(data[p2].y >= data[p3].y && data[p1].x <= data[p2].x) return true;
if(data[p2].y <= data[p3].y && data[p1].x >= data[p2].x) return true;
return false;
}
if(data[p1].x == data[p2].x) {
if(data[p1].y <= data[p2].y && data[p1].x <= data[p3].x) return true;
if(data[p1].y >= data[p2].y && data[p1].x >= data[p3].x) return true;
return false;
}
if(data[p1].x == data[p3].x) {
if(data[p1].y <= data[p3].y && data[p1].x >= data[p2].x) return true;
if(data[p1].y >= data[p3].y && data[p1].x <= data[p2].x) return true;
return false;
}

float k12 = (data[p1].y - data[p2].y) / (float)(data[p1].x - data[p2].x);
if(data[p1].x > data[p2].x && data[p3].y >= k12 * (data[p3].x - data[p1].x) + data[p1].y) return true;
if(data[p1].x < data[p2].x && data[p3].y <= k12 * (data[p3].x - data[p1].x) + data[p1].y) return true;
return false;
}

double multiply(node& sp, node& ep, node& op) {
return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
}


//判断方法为快速排斥实验跟跨立实验
//如果两条线段相交就返回false,通过order数组来构造线段
//其中最后一条肯定不会与新加入的线段相交(除了那顶点)
bool line_can(int p, int count) {
if(count <= 1) return true;
//当新加入的线段的终点为起点时(第1个点),则不用判断从第一个点出发的线段
if(p != 0) {
if((max(data[p].x, data[order[count]].x) >= min(data[0].x, data[order[0]].x))&&
(max(data[0].x, data[order[0]].x) >= min(data[p].x, data[order[count]].x))&&
(max(data[p].y, data[order[count]].y) >= min(data[0].y, data[order[0]].y))&&
(max(data[0].y, data[order[0]].y) >= min(data[p].y, data[order[count]].y))&&
(multiply(data[0], data[order[count]], data[p]) * multiply(data[order[count]], data[order[0]], data[p]) >= 0)&&
(multiply(data[p], data[order[0]], data[0]) * multiply(data[order[0]], data[order[count]], data[0]) >= 0))
return false;
}

//判断以访问的点依次构成的线段与新加入的线段是否相交,
//其中最后一条肯定不会与新加入的线段相交(除了那顶点),故不用判断。
for(int i = 0; i <= count - 2; i++) {
if((max(data[p].x, data[order[count]].x) >= min(data[order[i]].x, data[order[i + 1]].x))&&
(max(data[order[i]].x, data[order[i + 1]].x) >= min(data[p].x, data[order[count]].x))&&
(max(data[p].y, data[order[count]].y) >= min(data[order[i]].y, data[order[i + 1]].y))&&
(max(data[order[i]].y, data[order[i + 1]].y) >= min(data[p].y, data[order[count]].y))&&
(multiply(data[order[i]], data[order[count]], data[p]) * multiply(data[order[count]], data[order[i + 1]], data[p]) >= 0)&&
(multiply(data[p], data[order[i + 1]], data[order[i]]) * multiply(data[order[i + 1]], data[order[count]], data[order[i]]) >= 0))
return false;
}
return true;
}

void dfs(int last, int cur, int count) {
if(cur == 0) {
_max = max(_max, count - 1);
return ;
}
for(int i = 0; i < n && _max != n - 1; i++) {
if(!isVis[i] && angle_can(last, cur, i) && line_can(i, count)) {
isVis[i] = true;
order[count + 1] = i;
dfs(cur, i, count + 1);
isVis[i] = false;
}
}
}

int main() {
freopen("C:/Users/Alfred/Desktop/1.txt", "r", stdin);
cin >> n;
memset(isVis, false, sizeof(isVis));
for(int i = 0; i < n; i++) {
cin >> data[i].x >> data[i].y;
}
for(int i = 1; i < n && _max != n - 1; i++) {
if(angle_can(0, 1, i)) {
isVis[i] = true;
order[0] = i;
dfs(0, i, 0);
isVis[i] = false;
}
}
cout << _max << endl;
return 0;
}
...全文
163 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
logiciel 2011-01-29
  • 打赏
  • 举报
回复
我觉得应该输出1,可以从第2个岛右转180度回到第1个岛。
logiciel 2011-01-29
  • 打赏
  • 举报
回复
根据题意,右转0度也算是右转.请试以下输入:
5
1 1
1 2
1 3
1 4
1 5
alfredtofu 2011-01-29
  • 打赏
  • 举报
回复
这个我不解了,输出是2,我觉得应该是0,因为题目说了不能重复走,这应该是0。
[Quote=引用 8 楼 logiciel 的回复:]

根据题意,右转0度也算是右转.请试以下输入:
5
1 1
1 2
1 3
1 4
1 5
[/Quote]
alfredtofu 2011-01-28
  • 打赏
  • 举报
回复

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
using namespace std;

struct node {
int x;
int y;
}data[1001];

int _max = 0;
bool isVis[1001];
int n;
int order[1001]; //存放已经访问的点,按访问顺序存放

//叉积
int cp(int p1, int p2, int p3) {
int x1 = data[p3].x - data[p1].x;
int y1 = data[p3].y - data[p1].y;
int x2 = data[p2].x - data[p1].x;
int y2 = data[p2].y - data[p1].y;
return x1 * y2 - x2 * y1;
}

bool rotate_can(int p1, int p2, int p3) {
if(cp(p1, p2, p3) >= 0) return true;
return false;
}

bool isIn(int point, int beg, int end) {
if(data[point].x >= min(data[beg].x, data[end].x) &&
data[point].x <= max(data[beg].x, data[end].x) &&
data[point].y >= min(data[beg].y, data[end].y) &&
data[point].y <= max(data[beg].y, data[end].y))
return true;
return false;
}

bool isCross(int p1, int p2, int p3, int p4) {
int d1 = cp(p3, p4, p1);
int d2 = cp(p3, p4, p2);
int d3 = cp(p1, p2, p3);
int d4 = cp(p1, p2, p4);
if(d1 * d2 < 0 && d3 * d4 < 0) return true;
if(d1 == 0 && isIn(p1, p3, p4)) return true;
if(d2 == 0 && isIn(p2, p3, p4)) return true;
if(d3 == 0 && isIn(p3, p1, p2)) return true;
if(d4 == 0 && isIn(p4, p1, p2)) return true;
return false;
}

bool line_can(int p, int count) {
if(count <= 1) return true;

if(p != 0 && isCross(0, order[0], order[count], p))
return false;

for(int i = 0; i <= count - 2; i++) {
if(isCross(order[i], order[i + 1], order[count], p))
return false;
}
return true;
}

void dfs(int last, int cur, int count) {
if(cur == 0) {
_max = max(_max, count);
return;
}
for(int i = 0; i < n && _max != n - 1; i++) {
if(!isVis[i] && rotate_can(last, cur, i) && line_can(i, count)) {
isVis[i] = true;
order[count + 1] = i;
dfs(cur, i, count + 1);
isVis[i] = false;
}
}
}

int main() {
//freopen("C:/Users/Alfred/Desktop/1.txt", "r", stdin);
memset(isVis, false, sizeof(isVis));
cin >> n;
for(int i = 0; i < n; i++) {
cin >> data[i].x >> data[i].y;
}
isVis[1] = true;
order[0] = 1;
dfs(0, 1, 0);
cout << _max << endl;
return 0;
}
alfredtofu 2011-01-28
  • 打赏
  • 举报
回复
嗯,这个应是3,我后来发现我的判断出问题,但是改了还是WA。。
[Quote=引用 5 楼 logiciel 的回复:]

设输入是:
4
1 1
1 2
2 2
2 1

LZ程序为何输出2?
[/Quote]
alfredtofu 2011-01-28
  • 打赏
  • 举报
回复
知道的回答一下。。谢谢
logiciel 2011-01-28
  • 打赏
  • 举报
回复
设输入是:
4
1 1
1 2
2 2
2 1

LZ程序为何输出2?
alfredtofu 2011-01-28
  • 打赏
  • 举报
回复
没人吗。。

65,210

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧