记录编号 93024 评测结果 AAAAAAAAAA
题目名称 [NOI 2003]智破连环阵 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 0.039 s
提交时间 2014-03-23 21:32:01 内存使用 0.59 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int SIZEN=200,INF=0x7fffffff/2;
class POINT{
public:
	int x,y;
};
int dist2(POINT a,POINT b){
	return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
POINT fort[SIZEN],bomb[SIZEN];//碉堡和炸弹
bool shoot[SIZEN][SIZEN]={0};//炸弹i是否能炸到碉堡j
int destroy[SIZEN][SIZEN]={0};//炸弹i从j开始能炸到哪
bool single[SIZEN][SIZEN]={0};//碉堡i~j能否被单发摧毁
vector<int> next[SIZEN];//这次从某一个点开始,本次轰炸的终点可能是哪些点
int minclear[SIZEN]={0};//清除从这个点~M至少需要几发
int M,n,K,K2;
void init(void){
	scanf("%d%d%d",&M,&n,&K);
	K2=K*K;
	for(int i=1;i<=M;i++) scanf("%d%d",&fort[i].x,&fort[i].y);
	for(int i=1;i<=n;i++) scanf("%d%d",&bomb[i].x,&bomb[i].y);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=M;j++){
			if(dist2(bomb[i],fort[j])<=K2) shoot[i][j]=true;
			else shoot[i][j]=false;
		}
	}
	for(int i=1;i<=n;i++){
		destroy[i][M+1]=M;
		for(int j=M;j>=1;j--){
			if(shoot[i][j]) destroy[i][j]=destroy[i][j+1],single[j][destroy[i][j]]=true;
			else destroy[i][j]=j-1;
		}
	}
	for(int i=1;i<=M;i++){
		for(int j=M;j>=i;j--){
			if(single[i][j]){
				for(int k=i;k<=j;k++) single[i][k]=true;
				break;
			}
		}
	}
	for(int i=1;i<=M;i++) for(int j=i;j<=M;j++) if(single[i][j]) next[i].push_back(j);
	minclear[M+1]=0;
	for(int i=M;i>=1;i--) minclear[i]=1+minclear[next[i].back()+1];
}
vector<int> c[SIZEN];
bool cn[SIZEN][SIZEN]={0};
int visit[SIZEN]={0};
int match[SIZEN]={0};
int nowplan[SIZEN]={0};//现在段对炸弹的对应
int ans=INF;
int oplan[SIZEN]={0};
void addseg(int u,int v,int pos){
	for(int i=1;i<=n;i++){
		for(int j=u;j>=1;j--){
			if(destroy[i][j]>=v) cn[pos][i]=true;
			if(destroy[i][j]>=v) c[pos].push_back(i);
		}
	}
}
int findpath(int x){
	for(int u=1;u<=n;u++){
		if(!cn[x][u]||visit[u]) continue;
		visit[u]=true;
		if(!match[u]||findpath(match[u])){
			match[u]=x;
			nowplan[x]=u;
			return u;
		}
	}
	return 0;
}
void DFS(int x,int used){//现在分了used段,编号小于x的碉堡均已爆破
	if(used+minclear[x]>=ans) return;
	if(x>M){
		ans=used;
		memset(oplan,0,sizeof(oplan));
		memcpy(oplan,nowplan,sizeof(oplan[0])*(n+1));
		return;
	}
	used++;
	c[used].clear();
	memset(cn[used],0,sizeof(cn[used]));
	for(int i=next[x].size()-1;i>=0;i--){
		int u=next[x][i];
		addseg(x,u,used);
		memset(visit,0,sizeof(visit));
		int nowp=findpath(used);
		if(nowp) DFS(u+1,used);
		match[nowplan[used]]=0;
		nowplan[used]=0;
	}
}
int main(){
	freopen("zplhz.in","r",stdin);
	freopen("zplhz.out","w",stdout);
	init();
	DFS(1,0);
	printf("%d\n",ans);
	for(int i=1;i<=ans;i++) printf("%d ",oplan[i]);
	printf("\n");
	return 0;
}