poj 1230 Pass-Muraille 题目链接:http://poj.org/problem?id=1230
贪心水
题目大意:魔术师要表演穿墙魔术,舞台上有墙,魔术师有k单位的能量,也就是说他能穿过k面墙,但舞台上的墙可能会有多于k面的情况,问最少要拆几面墙,使得魔术师能表演成功?
题目分析:舞台是一个二维数组,墙都是横的,魔术师表演时则是按列走,所以我想可以用一个一维数组存下当前每一列的状态(有多少层墙),然后通过遍历一维数组来判断这一列是拆还是不拆。如果需要拆,就要选择拆哪一面(拆墙一拆拆一面,而不是拆一格,一开始没理解好),分析可得,拆对后面影响最大的墙是最优方案,也就是要拆从此点到右边距离最远的一面(或几面墙)。代码中拆墙动作循环边界为j<status[i]-k+j,最后还要加个j,原因是每拆一面墙,status[i]当前位置就要减1,边界变了,要使它不变,就要加上j。
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int wl,wr,wtr;//wall left,wall right,wall to right
}wall[150];
int cmp(node a,node b)
{
return a.wtr>b.wtr?1:0;
}
int main()
{
int t,n,k,nothing,status[150],max_r,ans;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
ans=max_r=0;
memset(status,0,sizeof(status));
for(int i=0;i<n;i++)
{
scanf("%d%d%d%d",&wall[i].wl,¬hing,&wall[i].wr,¬hing);
if(wall[i].wl>wall[i].wr)//坑啊,一开始没注意到这个
{
nothing=wall[i].wl;
wall[i].wl=wall[i].wr;
wall[i].wr=nothing;
}
if(wall[i].wr>max_r)max_r=wall[i].wr;
for(int j=wall[i].wl;j<=wall[i].wr;j++)
{
status[j]++;
}
}
for(int i=0;i<=max_r;i++)
{
// printf("status[%d]-%d=%d\n",status[i],k,status[i]-k);
if(status[i]>k)
{
for(int j=0;j<n;j++)//找对后面影响最远的
{
if(wall[j].wl>i)wall[j].wtr=0;//把当前列无墙的赋0
else wall[j].wtr=wall[j].wr-i;
}
sort(wall,wall+n,cmp);
for(int j=0;j<status[i]-k+j;j++)//拆墙的动作在这里 改了 !!!!!!!
{
//printf("走了一遍j=%d,status[i]-k=%d\n",j,status[i]-k);
for(int jk=wall[j].wl;jk<=wall[j].wr;jk++)
{
status[jk]--;//具体拆,状态减
}
for(int jk=0;jk<=max_r;jk++)
{
// printf("%d",status[jk]);
}
//putchar('\n');
wall[j].wl=wall[j].wr=wall[j].wtr=0;//拆完赋0
ans++;
}
//sort(wall,wall+n,cmp);
//n-=status[i]-k;
}
}
printf("%d\n",ans);
}
return 0;
}/*
1
8 2
0 0 0 0
0 1 0 1
5 0 5 0
5 1 5 1
1 1 4 1
0 2 2 2
3 2 5 2
4 3 1 3
*/
/*
1
5 2
1 0 1 0
1 0 1 0
1 9 1 9
1 9 1 9
1 2 1 2
*/
/*
1
4 2
1 0 1 0
1 3 1 3
1 9 1 9
1 2 1 2
*/
PS:实在不容易,一个小错折腾了一天多,code中带的测试数据后两个对我的错误有参考意义,很多网上的测试数据都对了,但还是WA,无语……
http://blog.sina.com.cn/s/blog_64018c250100wkju.html这篇blog很厉害的样子,最下面那个程序像是生成测试数据用的,不大懂……