算法竞赛入门经典 笔记(1)

P144 UVa12657 移动盒子 Boxes in a Line

#include<cstdio>
typedef long long LL;
LL n,m;
LL l[100010],r[100010],p;//双向链表
LL case1;//记录这是第几种情况
int main()
{
	LL t,ans,i,a,x,y,k;
	while(scanf("%lld%lld",&n,&m)==2)
	{
		p=0;//记录现在顺序是正的还是反的
		for(i=1;i<=n;i++)
		{
			l[i]=i-1;r[i]=i+1; 
		}
		for(i=1;i<=m;i++)
		{
			scanf("%lld",&a);
			if(a==4)
				p=!p;
			else
			{
				if(a!=3&&p)	a=3-a;//忘了加导致错,因为如果p不为0表示顺序是颠倒的
				//而我们只是记录了p,并没有实际颠倒过来,因此p不为0时操作左侧实际要右侧,操作右侧实际要操作左侧
				scanf("%lld%lld",&x,&y);
				if(a==1)
				{
					if(x==l[y])	continue;//忘了加,其实可以不加
					r[l[x]]=r[x];
					l[r[x]]=l[x];
					r[l[y]]=x;
					l[x]=l[y];
					r[x]=y;
					l[y]=x;
				}
				if(a==2)
				{
					if(x==r[y])	continue;//忘了加,其实可以不加
					r[l[x]]=r[x];
					l[r[x]]=l[x];
					l[r[y]]=x;
					r[x]=r[y];
					l[x]=y;
					r[y]=x;
				}
				if(a==3)
				{
					if(r[y]==x)
					{
						t=y;
						y=x;
						x=t;
					}
					if(r[x]==y)
					{
						r[l[x]]=y;
						l[r[y]]=x;
						l[y]=l[x];
						r[x]=r[y];
						l[x]=y;
						r[y]=x;
					}
					//曾经忽略了x、y相邻时交换的特殊情况,就是上面的情况,导致错误
					else
					{
						r[l[x]]=y;
						r[l[y]]=x;
						l[r[x]]=y;
						l[r[y]]=x;
						t=r[x];
						r[x]=r[y];
						r[y]=t;
						t=l[x];
						l[x]=l[y];
						l[y]=t;
					}
				}
			}
		}
		t=0;
		ans=0;
		if(p==0)
		{
			for(i=1;i<=n;i++)
				if(l[i]==0)
				{
					k=i;
					while(k!=n+1)
					{
						t=not t;
						if(t)
							ans+=k;
						k=r[k];
					} 
					break;
				}
		}
		else
		{
			for(i=1;i<=n;i++)
				if(r[i]==n+1)
				{
					k=i;
					while(k!=0)
					{
						t=not t;
						if(t)
							ans+=k;
						k=l[k];
					}
				}
		}
		printf("Case %lld: %lld
",++case1,ans); 
	}
	return 0;
}

P138 UVa212 医院设备利用 Use of Hospital Facilities

#include<iostream>
#include<cstring>
//出过错:病人要去的恢复室,是根据做完手术那一刻编号最小的空的恢复室决定的
//而不是到之后编号最小的空的恢复室
//出过错:那个the patient with the lower number指的是在门牌号小的手术室做手术的患者。那个number竟然指的门牌号!http://www.cnblogs.com/xienaoban/p/6798078.html
#include<string>
#include<queue>
using namespace std;
struct Patient
{
	string name;
	int room,b1,e1,bed,b2,e2;//分别记录病人的手术室,手术开始时间,手术结束时间,恢复室,恢复开始时间,恢复结束时间
	int t1,t2;//分别记录病人的手术和恢复时间
}pt[110];
int rm[11],bd[31];//记录room和bed的使用时间
struct Query
{
	int room,end,ptn;
	Query(){}
	Query(int b,int c,int d)
	{
		room=b;end=c;ptn=d;
	}
	friend bool operator<(const Query&a,const Query& b)
	{
		return (a.end>b.end)||(a.end==b.end&&a.room>b.room)||(a.end==b.end&&a.room==b.room&&a.ptn>b.ptn);
	}//这个排序对于病人做手术、从手术出来、恢复的排序都有效
};
int q_num=0;
priority_queue<Query> q1;
priority_queue<Query> q2;//记录病人从手术室出来的顺序(就是pop的顺序)、结束时间(end)、做手术的房间(room)
bool boo[31];
int n,m,T,t1,t2,t3,k,maxt;
int main()
{
	int i;
	while(scanf("%d%d%d%d%d%d%d",&n,&m,&T,&t1,&t2,&t3,&k)==7)//出过错:当成单组数据了
	{
		memset(boo,0,sizeof(boo));
		memset(rm,0,sizeof(rm));
		memset(bd,0,sizeof(bd));
		maxt=-1;
		T=60*T;
		for(i=1;i<=k;i++)
		{
			cin>>pt[i].name;
			scanf("%d%d",&pt[i].t1,&pt[i].t2);
		}
		Query qt,qt2;
		for(i=1;i<=min(n,k);i++)
		{
			q1.push(Query(i,pt[i].t1+T,i));
			pt[i].b1=T;
			pt[i].room=i;
		}
		for(i=min(n,k)+1;i<=k;i++)
		{
			qt=q1.top();
			q1.pop();
			rm[qt.room]+=pt[qt.ptn].t1;
			pt[qt.ptn].e1=qt.end;
			q1.push(Query(qt.room,qt.end+t2+pt[i].t1,i));
			pt[i].b1=qt.end+t2;
			pt[i].room=qt.room;
			q2.push(Query(qt.room,qt.end,qt.ptn));
		}
		while(!q1.empty())
		{
			qt=q1.top();
			q1.pop();
			rm[qt.room]+=pt[qt.ptn].t1;
			pt[qt.ptn].e1=qt.end;
			q2.push(Query(qt.room,qt.end,qt.ptn));
		}
	//	while(!q2.empty())
	//	{
	//		qt=q2.top();
	//		q2.pop();
	//		printf("%d %d %d
",qt.end,qt.ptn,pt[qt.ptn].t2+qt.end);
	//	}
	//	for(i=1;i<=n;i++)
	//		printf("%d %d
",i,rm[i]);
	//	for(i=1;i<=k;i++)
	//		printf("%d %d %d
",pt[i].room,pt[i].b1,pt[i].e1);
		while(!q2.empty())
		{
			qt=q2.top();
			q2.pop();
			while(!q1.empty())
			{
				qt2=q1.top();
				if(qt2.end+t3<=qt.end)//出过错:没加等号
				{
					q1.pop();
					pt[qt2.ptn].e2=qt2.end;
					boo[qt2.room]=false;
					bd[qt2.room]+=pt[qt2.ptn].t2;
					maxt=max(maxt,qt2.end);
				}
				else
					break;
			}
			for(i=1;i<=m;i++)
				if(boo[i]==false)
				{
					boo[i]=true;
					q1.push(Query(i,qt.end+pt[qt.ptn].t2+t1,qt.ptn));
					pt[qt.ptn].b2=qt.end+t1;
					pt[qt.ptn].bed=i;
					break;
				}
		}
		while(!q1.empty())
		{
			qt2=q1.top();
			q1.pop();
			maxt=max(maxt,qt2.end);
			bd[qt2.room]+=pt[qt2.ptn].t2;
			pt[qt2.ptn].e2=qt2.end;
		}
		printf(" Patient          Operating Room          Recovery Room
");  
	    printf(" #  Name     Room#  Begin   End      Bed#  Begin    End
");  
	    printf(" ------------------------------------------------------
");
		for(i=1;i<=k;i++)
			printf("%2d  %-10s%2d   %2d:%02d   %2d:%02d     %2d   %2d:%02d   %2d:%02d
",i,pt[i].name.c_str(),pt[i].room,pt[i].b1/60,pt[i].b1%60,pt[i].e1/60,pt[i].e1%60,pt[i].bed,pt[i].b2/60,pt[i].b2%60,pt[i].e2/60,pt[i].e2%60);
		printf("
Facility Utilization
Type  # Minutes  % Used
");
		printf("-------------------------
");
		maxt-=T;
		for(i=1;i<=n;i++)
			printf("Room %2d    %4d   %5.2f
",i,rm[i],(double)rm[i]*100/maxt);
		for(i=1;i<=m;i++)
			printf("Bed  %2d    %4d   %5.2f
",i,bd[i],(double)bd[i]*100/maxt);
		printf("
");//注意:不要少空行
	}
	return 0;
}

P148 UVa 679 小球下落 Dropping Balls

点击打开链接


记在滚某个球时,滚到节点i的次数为a[i]

显然,如果a[i]为奇数,那么a[i*2]为(a[i]+1)/2,a[i*2+1]为(a[i]-1)/2(如果直接整除的话也可以表示为a[i]/2)

(原因是a[i]为奇数,那么前面a[i]-1次必定是左右各走(a[i]-1)/2次,这一次必定是向左走)

如果a[i]为偶数,那么a[i*2]=a[i*2+1]=a[i]/2

而且如果a[i]为奇数,那么下一步会往a[i*2]走

如果a[i]为偶数,那么下一步会往a[i*2+1]走

显然a[1]就是题目中的I,那么现在可以求出叶子节点了

这再次说明了写程序不如多想想

P154

对比:

#include<cstdio>
int b[100000001];
int *a;
int main()
{
	int i;
	a=(int*)&b;
	*a=29;
	for(int i=1;i<=100000000;i++)
		*(a+i)=(*(a+i-1)+*(a+i-2))*2%10000000;
	printf("%d",*(a+10000000));
}
#include<cstdio>
int b[100000001];
int *a;
int main()
{
	int i;
	a=(int*)&b;
	*a=29;
	for(i=1;i<=100000000;i++)
		b[i]=(b[i-1]+b[i-2])*2%10000000;
	printf("%d",b[10000000]);
}
内存池

P160 UVa 297 四分树 Quadtrees

输出测试数据(?):

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
int a[33][33];
void print(int l1,int l2,int w)
{
	bool b1=false,b2=false;
	int i,j;
	if(w==1)
	{
		if(a[l1][l2]==0)
			printf("e");
		else
			printf("f");
		return;
	}
	for(i=0;i<w;i++)
		for(j=0;j<w;j++)
		{
			if(a[l1+i][l2+j]==0)
				b1=true;
			if(a[l1+i][l2+j]==1)
				b2=true;
			if(b1&&b2)
				goto haha;
		}
	haha:
	if(b1&&(!b2))
		printf("e");
	else if((!b1)&&b2)
		printf("f");
	else
	{
		printf("p");
		print(l1+w/2,l2,w/2);
		print(l1,l2,w/2);
		print(l1,l2+w/2,w/2);
		print(l1+w/2,l2+w/2,w/2);
	}
}
int main()
{
	int i,j;
	srand(time(0));
	printf("1
");
	memset(a,0,sizeof(a));
	for(i=1;i<=32;i++)
		for(j=1;j<=32;j++)
			a[i][j]=rand()%2;
	print(1,1,32);
	printf("
");
	for(i=1;i<=32;i++)
		for(j=1;j<=32;j++)
			a[i][j]=rand()%2;
	print(1,1,32);
}
程序:

#include<cstdio>
#include<cstring>
int ans;//答案
int buf[35][35];//记录draw出来的正方形
char s[2000];//曾经未注意,开太小了,实际上最大远远大于32*32,因为一个2*2的格子,最多占5个字符而不是4个,更多的类似 
int p,n;//当前字符序号
//把s绘制到以(r,c)为左上角,边长为w的buf中
void draw(const char* s,int r,int c,int w)
{
	char ch=s[p++];
	int i,j; 
	if(ch=='p')
	{
		draw(s,r+w/2,c,w/2);
		draw(s,r,c,w/2);
		draw(s,r,c+w/2,w/2);
		draw(s,r+w/2,c+w/2,w/2);
		//举例:最开始0-31,0-31
		/*分开:
		1:16-31,0-15
		2:0-15,0-15
		3:0-15,16-31
		4:16-31,16-31
		*/
	}
	else if(ch=='f')
		for(i=0;i<w;i++)
			for(j=0;j<w;j++)
				if(buf[r+i][c+j]==0)
				{
					ans++;
					buf[r+i][c+j]=1;
				}
}
int main()
{
	int i;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		ans=0;
		//memset(s,0,sizeof(s));
		memset(buf,0,sizeof(buf)); 
		scanf("%s",s);
		p=0;
		draw(s,0,0,32);
		scanf("%s",s);
		p=0;
		draw(s,0,0,32);
		printf("There are %d black pixels.
",ans);
	}
	return 0;
}


原文地址:https://www.cnblogs.com/hehe54321/p/8470439.html