USACO 2016 January Contest Gold T3: Lights Out

题目大意

说按顺时针顺序给你N(4N200)个点,围成一个N边形农场。贝西要从某一点p出发走道农场1,她不知道自己在哪个点。

她先按顺时针顺序走若干个点,记录下她所走的每条边的长度和每次转弯的角度,如果从当前记录的信息能够准确判断她所在的位置,她就可以选择继续以往前走或掉头往回走两种方式中距离较短的方式来走道1

现求对于所有不同的出发点,从原位置直接走到1的较短路径(顺或逆时针走)和贝西以上述的这种方式走出的路径长度的差值的最大值。

备注:所给农场所有的边均水平或竖直,记录“转弯的角度”可以理解为记录转了90°或270°,即顺时针转弯或逆时针转弯。

题目分析

考虑如何通过当前已经记录的信息来唯一确定贝西的位置。如果能,那么贝西此时就可以决策是要顺时针还是要逆时针一路走到1;否则贝西还要继续前进并记录信息。

考虑记录所有路径信息,我们把一个路径长度和一个转角度数两个信息对应拼接在一起,

这样可以将的整个路径视作一个字符串。这样的记录以后,我们仅需判断当前已走出的路径仅为一条路径的前缀。如果是,就可以确定当前位置。

将问题转化为字符串问题以后,对于判断前缀,我们可以想到许多方法。例如:字典树,哈希等。但是本题由于N较小,因此大可不必这么麻烦。

我们用multiset(防去重)存下所有的前缀,然后在multiset里查找即可。

对于是顺时针还是逆时针旋转,用叉积判断一下即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN=205;
 4 
 5 struct Node{
 6     int x,y;
 7 }a[MAXN];
 8 int n,f[MAXN];
 9 inline void Cir(int &x){
10     if(x==n+1) x=1;
11     if(x==n+2) x=2;
12     if(x==0) x=n;
13 }
14 inline int CrossProduct(int x,int y,int xx,int yy){
15     return x*yy-xx*y;
16 } 
17 inline int dis(int i,int j){
18     return fabs(a[i].x-a[j].x)+fabs(a[i].y-a[j].y);
19 }
20 vector<int> s;
21 int main(){
22     s.push_back(0);
23     scanf("%d",&n);
24     for(int i=1;i<=n;++i)
25         scanf("%d%d",&a[i].x,&a[i].y);
26     for(int i=1;i<=n;++i){
27         int j=i+1,k=i+2;
28         Cir(j);Cir(k);
29         s.push_back(dis(i,j));
30         if(CrossProduct(a[j].x-a[i].x,a[j].y-a[i].y,a[k].x-a[j].x,a[k].y-a[j].y)>0)
31             s.push_back(-1);
32         else
33             s.push_back(-2);
34     }
35     s.back()=0;
36     for(int i=2;i<=n;++i){
37         int j=i+1;Cir(j);
38         int tmp1=dis(i,j);
39         while(j!=1){
40             int jj=j;
41             ++j;Cir(j);
42             tmp1+=dis(jj,j);
43         }
44         j=i-1;Cir(j);
45         int tmp2=dis(i,j);
46         while(j!=1){
47             int jj=j;
48             --j;Cir(j);
49             tmp2+=dis(jj,j);
50         }
51         f[i]=min(tmp1,tmp2);
52     }
53     multiset<vector<int> >ss;
54     for(int i=0;i<(int)s.size();i+=2){
55         for(int j=1;i+j<=(int)s.size();j+=2)
56             ss.insert(vector<int>(s.begin()+i,s.begin()+i+j));
57     }
58     //cout<<1<<endl;
59     int ans=0;
60     for(int i=2;i<=n;++i){
61         int j,cst=0;
62         for(j=1;;j+=2){
63             if(ss.count(vector<int>(s.begin()+(i-1)*2,s.begin()+(i-1)*2+j))==1)
64                 break;
65             cst+=s[(i-1)*2+j];
66         }
67         ans=max(ans,cst+f[i+j/2]-f[i]);
68     }
69     cout<<ans<<endl;
70     return 0;
71 }
原文地址:https://www.cnblogs.com/LI-dox/p/11215985.html