UVa 11134 Fabled Rooks 虚拟的车 - 贪心+思维

给一个n x n的棋盘,要求在上面放n个车且相互不攻击,而且对于第i个车要求必须在给定的矩形中(每个车所对应的矩形已给出),求一组满足的解,无满足的情况输出”IMPOSSIBLE”

首先考虑拆点,将二维座标拆成x轴和y轴的两组,对于每一个轴要求在给定的n个线段上选出一个1~n的排列。

如果考虑每条线段只能选择一个数,每个数的选择只能取一次,满足二分图的性质,可以考虑拿最大匹配写(写了个Hangary然后就T了一屏,Dinic或者HC可能会好点,懒得写了)

只能贪心了。研究紫书发现一个很有趣的思路,就是线段之间的包含关系。若某一线段被包含,则这个线段一定比包含他的大区间先要被考虑。线段之间包含关系作为突破口解决贪心问题的情况很常见。
先考虑大区间包含小区间的情况,大区间很明显比小区间的满足可能更大,优先考虑小区间总不会更差,于是对于一个区间,先忽略所有嵌套它的大区间。于是先抛开大区间,剩下的都是不相容的小区间,这些小区间从左向右排序,对于每一个区间可能优先考虑靠左的没有用过的点。当一个大区间内的所有小区间都被讨论完后再讨论大区间,思考实现的方式,即如何排序可以做到这一点:
先按右端点升序,再左端点降序,这样可以保证小区间绝对在大区间之前,而且不相容的小区间本身有序。(都是套路啊啊啊)

然后附上WA了n次才调对的代码:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm> 

using namespace std;

const int maxn=5005;

struct node
{
    int x,y,id;
    bool operator < (const node &tmp) const
    {
        return y<tmp.y||(y==tmp.y&&x>tmp.x);
    }
}qx[maxn],qy[maxn];

int n,linkx[maxn],linky[maxn];
bool flag,vst[maxn];

void solve(node q[],int link[])
{
    sort(q+1,q+n+1);
    memset(vst+1,0,sizeof(bool)*n);
    for(int i=1;i<=n;i++)
    {
        int pos=q[i].x;
        while(pos<=q[i].y&&vst[pos])pos++;
        if(pos<=q[i].y)link[q[i].id]=pos,vst[pos]=true;
        else{flag=false;return;}
    }
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        flag=true;
        for(int i=1;i<=n;i++)
            scanf("%d%d%d%d",&qx[i].x,&qy[i].x,&qx[i].y,&qy[i].y),
            qx[i].id=qy[i].id=i;
        solve(qx,linkx);
        solve(qy,linky);
        if(!flag){puts("IMPOSSIBLE");continue;}
        for(int i=1;i<=n;i++)
            printf("%d %d\n",linkx[i],linky[i]);
    }
    return 0;
}

外加一份Hangary(TLE):

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm> 

using namespace std;

const int maxn=5005;

struct node
{
    int x,y;
}qx[maxn],qy[maxn];
struct edge
{
    int to,next;
}e[maxn*maxn];

int n,cnt,T;
int head[maxn],matchx[maxn],matchy[maxn],vst[maxn];

void insert(int a,int b)
{
    e[++cnt].to=b;e[cnt].next=head[a];head[a]=cnt;
}
bool find(int x,int match[])
{
    int y;
    for(int i=head[x];i;i=e[i].next)if(vst[y=e[i].to]!=T)
    {
        vst[y]=T;
        if(!match[y]||find(match[y],match))
        {
            match[y]=x;
            return true;
        }
    }
    return false;
}
int hangary(node q[],int match[])
{
    cnt=0;
    int num=0;
    memset(head+1,0,sizeof(int)*n);
    memset(vst+1,0,sizeof(int)*n);
    memset(match+1,0,sizeof(int)*n);
    for(int i=1;i<=n;i++)
    {
        for(int j=q[i].x;j<=q[i].y;j++)
        insert(j,i);
    }
    for(int i=1;i<=n;i++)T=i,num+=find(i,match);
    if(num<n)return false;
    return true;
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        for(int i=1;i<=n;i++)
            scanf("%d%d%d%d",&qx[i].x,&qy[i].x,&qx[i].y,&qy[i].y);
        if(hangary(qx,matchx)&&hangary(qy,matchy))
            for(int i=1;i<=n;i++)printf("%d %d\n",matchx[i],matchy[i]);
        else puts("IMPOSSIBLE");
    }
    return 0;
}

闲得蛋疼又交了一波网络流然后又T了。。。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm> 

using namespace std;

const int maxn=5005;

struct node
{
    int x,y;
}qx[maxn],qy[maxn];
struct edge
{
    int to,next,val;
}e[(maxn*maxn)<<1];

int n,cnt,T;
int head[maxn<<1],matchx[maxn],matchy[maxn],depth[maxn<<1];

#define S 0
#define T (n<<1)+1

void insert(int a,int b)
{
    e[++cnt].to=b;e[cnt].next=head[a];e[cnt].val=1;head[a]=cnt;
    e[++cnt].to=a;e[cnt].next=head[b];e[cnt].val=1;head[b]=cnt;
}
bool bfs()
{
    queue<int>q;
    q.push(S);
    memset(depth,0,sizeof depth);
    depth[S]=1;
    while(!q.empty())
    {
        int u=q.front(),v;q.pop();
        for(int i=head[u];i;i=e[i].next)
            if(!depth[v=e[i].to]&&e[i].val)
            {
                depth[v]=depth[u]+1;
                q.push(v);
            }
    }   
    return depth[T];
}
int dfs(int match[],int x,int a)
{
    if(x==T||a==0)return a;
    int rest=a,y;
    for(int i=head[x];i;i=e[i].next)
        if(depth[y=e[i].to]==depth[x]+1&&e[i].val)
    {
        int cur=dfs(match,y,min(rest,e[i].val));
        e[i].val-=cur;
        e[i^1].val+=cur;
        if(y>n&&cur&&(~i&1))match[y-n]=x;
        rest-=cur;
        if(!rest)return a;
    }
    return a-rest;
}
int dinic(node q[],int match[])
{
    cnt=1;
    int num=0;
    memset(head,0,sizeof head);
    memset(match+1,0,sizeof(int)*n);
    for(int i=1;i<=n;i++)
    {
        for(int j=q[i].x;j<=q[i].y;j++)
            insert(j,i+n);
    }
    for(int i=1;i<=n;i++)
        insert(S,i),insert(i+n,T);
    int res=0;
    while(bfs())
        res+=dfs(match,S,0x3f3f3f3f);
    return res>=n;
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        for(int i=1;i<=n;i++)
            scanf("%d%d%d%d",&qx[i].x,&qy[i].x,&qx[i].y,&qy[i].y);
        if(dinic(qx,matchx)&&dinic(qy,matchy))
            for(int i=1;i<=n;i++)printf("%d %d\n",matchx[i],matchy[i]);
        else puts("IMPOSSIBLE");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章