NOJ [1201] Chihuo II - Eating in China

来源:互联网 发布:百度派 知乎 编辑:程序博客网 时间:2024/06/05 21:15
链接地址:http://ac.nbutoj.com/Problem/view.xhtml?id=1201

这题其实不难,总归算法就是凸包加水DP。
但是我一直RA,以为是凸包码错了,还新学了一个凸包的算法,发现又错了,最后才知道是忘了初始化。

题目意思很容易理解,就是洛天依去中国吃好吃的,然后经过了N个地方,每个地方都有坐标x和y表示。
洛天依游走的方法是独特的,她一定要先在最外面一圈的点找一个点开始出发,走完最外面的一圈,并且回到原点,然后再将剩下的地点按上面这样执行,直到走完所有的地方。这里就类似于找多个凸包,但是要注意不能组成凸包的时候。
接着,将这些凸包连起来,连起来的规则是在最外层凸包上找一顶点,然后在里面这层凸包找一顶点,连起来。重复操作,直到所有凸包都是连通的。最后让你输出最短路径的连线方案。这里就是DP问题了。

思路就是,先找到外面一层凸包,然后求出这个凸包的周长,并删除这些顶点。然后再在剩下的点里找一个凸包,求周长,并删除这些顶点,直到没有点剩下为止。
然后再将凸包连起来,得到的所有连线和凸包周长的总和就是答案了。

以下是我AC的代码。
#include <set>
#include <map>
#include <list>
#include <stack>
#include <queue>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const double INF = 2147483647.0f;
int l, n;//l为剩余的点的个数,n为总的点的个数
int pm;//存储凸包个数
double d;//存储距离
struct pt
{
double x, y;
bool used;
};
pt save[1010];//记录原始点
int s[1010];
pt tubao[1010][1010];//记录每个凸包的点坐标
int pn[1010];//记录每个凸包的点的个数
double dp[1010][1010];

bool mult(pt a, pt b, pt c)//极角判定
{
if ((a.x - c.x) * (b.y - c.y) >= (b.x - c.x) * (a.y - c.y)) return 1;
else return 0;
}

double dis(pt a, pt b)//计算两点间的点的距离
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

int cmp(const void *p, const void *q)//排序
{
if ((*(pt *)p).used != (*(pt *)q).used) return (*(pt *)p).used - (*(pt *)q).used;
else if ((*(pt *)p).x != (*(pt *)q).x) return (*(pt *)p).x - (*(pt *)q).x;
else return (*(pt *)p).y - (*(pt *)q).y;
}

int Andrew()
{
qsort(save, n, sizeof(save[0]), cmp);
s[0] = 0;
s[1] = 1;
if (l == 1) return 1;
if (l == 2) return 2;
int top = 1;
for (int i = 2; i < l; i++)
{
while (top && mult(save[i], save[s[top]], save[s[top - 1]])) top--;
s[++top] = i;
}
int len = top; s[++top] = l - 2;
for (int i = l - 3; i >= 0; i--)
{
while (top != len && mult(save[i], save[s[top]], save[s[top - 1]])) top--;
s[++top] = i;
}
return top;
}

int main()
{
while (~scanf("%d", &n))
{
memset(tubao, 0, sizeof(tubao));
memset(pn, 0, sizeof(pn));
memset(save, 0, sizeof(save));
for (int i = 0; i < n; i++)
{
scanf("%lf%lf", &(save[i].x), &(save[i].y));
save[i].used = 0;
}
pm = 0;
l = n;
d = 0;
while (l)
{
int t = Andrew();
if (t == 1) tubao[pm][0] = save[s[0]];
else for (int i = 0; i < t; i++)
{
d += dis(save[s[i]], save[s[(i + 1) % t]]);
tubao[pm][i] = save[s[i]];
save[s[i]].used = 1;
}
pn[pm] = t;
l -= t;
pm++;
}
double tap = INF;
for(int i = 0; i < pn[0]; i++)
{
dp[0][i] = 0;
}
for (int i = 1; i < pm; i++)
{
for (int j = 0; j < pn[i]; j++)
{
dp[i][j] = INF;
for (int k = 0; k < pn[i - 1]; k++)
{
dp[i][j] = min(dp[i][j], dp[i - 1][k] + dis(tubao[i][j], tubao[i - 1][k]));
if(i == pm - 1) tap = min(tap, dp[i][j]);
}
}
}
if(pm == 1) tap = 0;

printf("%.4lf\n", d + tap);
}

return 0;
}


0 0
原创粉丝点击