给一个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;
}