給一個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;
}