BZOJ1035Risk

11 篇文章 0 订阅
9 篇文章 0 订阅

可以先A掉一道弱化版本的题目 , UVa1334

我帮助Udebug重置了上面这个题数据 , 这个题目所需要考虑的可能类型非常少 , 只要你的算法没有错误 , 几乎是难以出错的。

提示:
1. 本题可以考虑卷包裹算法(aka PSLG)
2. 这是个训练指南上的中级习题 , 想作预备学习的小伙伴可以先看看训练指南中的计算几何部分。

说几个细节:

  • 本题从样例就可以看出有包围的情况 , 这不难想到解决方案。
  • 但如果你的解决方案过于限制于“回“字形这一中方案 , 可能会在【O】这种情形下出现问题
  • 不得不说SPOJ 上的数据很厉害 , 我尝试了数次都WA , 有在SPOJ上A了的小伙伴请帮帮我

调了很久 , 代码慎看

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <deque>
#include <stack>
#include <queue>
#include <algorithm>
#include <set>
#include <map>
#include <string>
#include <cassert>

using namespace std;

double eps = 1e-10;

int dcmp(double a) { return fabs(a)<eps?0:(a<0?-1:1); }

struct points
{
    double x , y;
    void read() { scanf("%lf%lf",&x,&y); }
    points(double x = 0 , double y = 0):x(x),y(y){}
    bool operator <(const points& b)const { return dcmp(x - b.x)==-1 || (dcmp(x - b.x)==0 && dcmp(y - b.y)==-1); }
    bool operator ==(const points& b)const { return dcmp(x - b.x)==0 && dcmp(y - b.y)==0; }
};

struct edge
{
    int b;
    int used , num;
    edge(int b = 0 , int used = 0 , int num = 0):b(b) , used(used) , num(num) {}
};

typedef points Vector;
typedef vector<points> polygon;

Vector operator +(Vector a , Vector b) { return Vector(a.x+b.x , a.y+b.y); }
Vector operator -(Vector a , Vector b ) { return Vector(a.x-b.x  , a.y-b.y); }
Vector operator *(Vector a , double b) { return Vector(a.x*b    , a.y*b   ); }
Vector operator /(Vector a , double b) { return Vector(a.x/b     , a.y/b   ); }

double Dot(Vector a , Vector b) { return a.x*b.x+a.y*b.y; }
double Cross(Vector a , Vector b)    { return a.x*b.y - b.x*a.y; }
double Length(Vector a) { return sqrt(Dot(a ,a )); }
double angle(Vector a , Vector b) { return acos(Dot(a , b)/Length(a)/Length(b)); }
double compareAngle( Vector a , Vector b ) { double res = angle(a , b); if(dcmp(Cross(a , b))<=0) res = -res; return res; }
bool onSegmenStrict(points p , points a , points b) { return dcmp(Cross(p-a , p-b))==0 && dcmp(Dot(p-a , p-b))==-1; }



int n , m;
const int maxn = 610;
const int maxm = 4100;
points cap[maxn];

int cnt;
map<points , int> dic;
points redic[maxm*2] ;
int tell(points a)
{
    if(dic.count(a)) return dic[a];
    redic[cnt] = a;
    return dic[a] = cnt++;
}

vector<edge> g[maxm*2];
vector<int> abj[maxm*2];
vector<int> nabj[maxm*2];
set<int> con[maxm*2];
int whoIsWho[maxm*2];
int rewhoisw[maxm*2];
vector<polygon> ps;
vector<vector<int> > mark;
int book[maxm*2];
edge e[maxm*2];
double s[maxm*2];
int st[maxm*2];

int inPolygon(points p , polygon& poly)
{
    int n = poly.size();
    int wn = 0;

    for(int i=0;i<n;i++)
    {
        int j = (i+1)%n;

        if(onSegmenStrict(p , poly[i] , poly[j]) || p == poly[i] || p== poly[j]) return 0;
        int k = dcmp(Cross(poly[j]-poly[i] , p - poly[i]));
        int d1 = dcmp(poly[i].y - p.y);
        int d2 = dcmp(poly[j].y - p.y);

        if(k>0 && d1<=0 && d2>0) wn++;
        if(k<0 && d2<=0 && d1>0) wn--;
    }
    return wn?-1:1;
}

double polygonArea(polygon& p)
{
    int n = p.size();
    double res = 0;
    for(int i=1;i<n-1;i++) res+= Cross(p[i] - p[0] , p[i+1] - p[0]);
    return res; 
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("risk6.in","r",stdin);
    #endif      
    while(scanf("%d%d",&n,&m)==2 && n+m)
    {
        cnt = 0;
        ps.clear();
        dic.clear();
        for(int i=0;i<n;i++) { cap[i].read(); }
        for(int i=0;i<m*2;i++) { g[i].clear() ; book[i] = 0; abj[i].clear(); con[i].clear(); }

        for(int i=0;i<m;i++)
        {
            points a , b;
            a.read();
            b.read();

            e[i*2] = edge(tell(b) , 0 , i*2);
            e[i*2+1] = edge(tell(a) , 0 , i*2+1);
            st[i*2] = tell(a);
            st[i*2+1] = tell(b);
            g[tell(a)].push_back(edge(tell(b) , 0 , i*2));
            g[tell(b)].push_back(edge(tell(a) , 0 , i*2+1));
            assert(tell(a) !=  tell(b));
        }

        //for(int i=0;i<cnt;i++) cout<<redic[i].x<<" "<<redic[i].y<<endl; cout<<endl<<endl;
        for(int i=0;i<2*m;i++) if(!book[i])
        {
            int now = e[i].b;
            Vector v = redic[e[i].b] - redic[st[i]];
            polygon ne;
            vector<int> nee;
            while(true)
            {               
                ne.push_back(redic[now]);

            //  if(now==0)
            //      cout<<"stay";
                int who = -1;
                //bool havesome = false;
                Vector Best;
                double bestAngle;
                for(int j=0;j<g[now].size();j++) if(!g[now][j].used)
                {
                    //havesome = true;
                    Vector here = redic[g[now][j].b] - redic[now];
                    if(v+here == Vector(0,0)) continue;
                    if(who == -1 || dcmp(compareAngle(v , here) - bestAngle)==1)
                    {
                        bestAngle = compareAngle(v , here);
                        //cout<<compareAngle(v , here)<<endl;
                        Best = here;
                        who = j;
                    }
                }
            //  if(havesome==false) cout<<now<<endl;
                //assert(havesome);
                if(who==-1) continue;
                g[now][who].used = 1;
                book[g[now][who].num] = 1;
                abj[g[now][who].num/2].push_back(ps.size());
                nee.push_back(g[now][who].num/2);

                if(now == st[i] && g[now][who].b == e[i].b) break; 
                //cout<<now<<"  "<<g[now][who].b<<endl;
                //cout<<redic[now].x<<" "<<redic[now].y<<" "<<" "<<redic[g[now][who].b].x<<" "<<redic[g[now][who].b].y<<endl;
                v = redic[g[now][who].b] - redic[now];
                now = g[now][who].b;
            }
            ps.push_back(ne);
            mark.push_back(nee);
        }
        //for(int i=0;i<m;i++){ cout<<i<<"    "; for(int j=0;j<abj[i].size();j++) cout<<abj[i][j]<<(j==abj[i].size()-1?"\n":" ");cout<<endl<<endl; }

        set<int> forbid;
        for(int i=0;i<ps.size();i++) if(dcmp(s[i] = polygonArea(ps[i]))<=0) forbid.insert(i);

        //cout<<forbid.size()<<endl;

    //  cout<<ps.size()<<endl;
    //  for(int i=0;i<ps.size();i++) for(int j=0;j<ps[i].size();j++) cout<<tell(ps[i][j])<<(j==ps[i].size()-1?"\n":" ");
    //  cout<<endl<<endl;   

        memset(rewhoisw , -1 , sizeof(rewhoisw));
        for(int i=0;i<n;i++)
        { 
            int wh = -1;
            double ar = 1e20;
            for(int j=0;j<ps.size();j++) if(forbid.count(j)==0 && inPolygon(cap[i] , ps[j])<=0)  if(dcmp(ar - s[j])>0) ar = s[j] , wh = j;

            assert(wh!=-1);
            whoIsWho[i] = wh;
            rewhoisw[wh] = i;
        }
        //for(int i=0;i<n;i++) cout<<whoIsWho[i]<<" "; cout<<endl<<endl;

        for(int i=0;i<m;i++) for(int j=0;j<abj[i].size();j++) if(rewhoisw[abj[i][j]]!=-1) nabj[i].push_back(abj[i][j]);
        for(int i=0;i<m;i++) abj[i] = nabj[i];
        for(int i=0;i<m;i++) if(abj[i].size()==2) 
            con[abj[i][0]].insert(abj[i][1]) , con[abj[i][1]].insert(abj[i][0]); 

        for(int i=0;i<ps.size();i++) if(rewhoisw[i]!=-1)
        {  
            bool ok = false;
            for(int j=0;j<mark[i].size();j++) if(abj[mark[i][j]].size()<2) { ok = true; break; }
            if(!ok) continue;

            int wh = -1;
            double ar = 1e20;
            for(int j=0;j<ps.size();j++)  if(i!=j && rewhoisw[j]!=-1)
            {
                bool ok = true;
                for(int k=0;k<ps[i].size();k++) if(inPolygon(ps[i][k] , ps[j])>=0) { ok = false; break; }
                if(!ok) continue;
                if(dcmp(ar - s[j])==1) ar = s[j] , wh = j;
            }
            if(wh!=-1) con[i].insert(wh) , con[wh].insert(i);
        } 

        for(int i=0;i<n;i++) 
        {
            cout<<con[whoIsWho[i]].size();
            vector<int> resnow;
            for(set<int>::iterator j=con[whoIsWho[i]].begin();j!=con[whoIsWho[i]].end();++j)
                resnow.push_back(rewhoisw[*j]+1);
            sort(resnow.begin() , resnow.end());
            for(int j=0;j<resnow.size();j++) printf(" %d",resnow[j]);
            printf("\n");
        }
    }


    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值