jzoj_1月27日D组

第一题(反射)

题意:

    给出一些镜子,有摆成'/'和'\'样子的,求一个光源照进来最多会在这些镜子中反射几次。

思路:

    光射进来有四个方向,我们可以设置一个变量记录方向状态,然后从四个方向来枚举并保存最大值,一开始我就是这样做的,然后因为一个细节浪费了很多时间。

代码:

#include<cstdio>
#include<cstring>
int fx,x,y,n,m,ans,s;//fx记录方向状态,从左射来是1,右是2,上是3,下是4
char c[1001][1001];
int max(int x,int y){return x>y?x:y;}
int main()
{
	freopen("mirror.in","r",stdin);
	freopen("mirror.out","w",stdout);
	scanf("%d%d",&n,&m);
	getchar();
	for (int i=1;i<=n;i++,getchar())
	  for (int j=1;j<=m;j++)
	  	c[i][j]=getchar();
	for (int i=1;i<=n;i++)
	{
		x=i;y=1;fx=1;//这里是从左边射来枚举
		while (x>=1&&x<=n&&y>=1&&y<=m)
		{
		 	if (c[x][y]=='/'&&fx==1) x--,fx=4;//如果从左射'/'会改变方向到上面,坐标也会改变
		 	else if (c[x][y]=='/'&&fx==2) x++,fx=3;//右射'/'会改变方向到下面
		 	else if (c[x][y]=='/'&&fx==3) y--,fx=2;//上射'/'会改变方向到左边
		 	else if (c[x][y]=='/'&&fx==4) y++,fx=1;//下射'/'会改变方向到右边
		 	else if (c[x][y]!='/'&&fx==1) x++,fx=3;//左射'\'会改变方向到下面
		 	else if (c[x][y]!='/'&&fx==2) x--,fx=4;//右射'\'会改变方向到上面
		 	else if (c[x][y]!='/'&&fx==3) y++,fx=1;//上射'\'会改变方向到右边
		 	else if (c[x][y]!='/'&&fx==4) y--,fx=2;//下射'\'会改变方向到左边
		 	s++;
	    } 
		ans=max(ans,s);
		s=0;
		x=i;y=m;fx=2;//右边
		while (x>=1&&x<=n&&y>=1&&y<=m)
		{
		 	if (c[x][y]=='/'&&fx==1) x--,fx=4;
		 	else if (c[x][y]=='/'&&fx==2) x++,fx=3;
		 	else if (c[x][y]=='/'&&fx==3) y--,fx=2;
		 	else if (c[x][y]=='/'&&fx==4) y++,fx=1;
		 	else if (c[x][y]!='/'&&fx==1) x++,fx=3;
		 	else if (c[x][y]!='/'&&fx==2) x--,fx=4;
		 	else if (c[x][y]!='/'&&fx==3) y++,fx=1;
		 	else if (c[x][y]!='/'&&fx==4) y--,fx=2;
		 	s++;
	    } 
	    ans=max(ans,s);
	    s=0;
	}
	for (int i=1;i<=m;i++)
	{
		x=1;y=i;fx=3;//上面
		while (x>=1&&x<=n&&y>=1&&y<=m)
		{
		 	if (c[x][y]=='/'&&fx==1) x--,fx=4;
		 	else if (c[x][y]=='/'&&fx==2) x++,fx=3;
		 	else if (c[x][y]=='/'&&fx==3) y--,fx=2;
		 	else if (c[x][y]=='/'&&fx==4) y++,fx=1;
		 	else if (c[x][y]!='/'&&fx==1) x++,fx=3;
		 	else if (c[x][y]!='/'&&fx==2) x--,fx=4;
		 	else if (c[x][y]!='/'&&fx==3) y++,fx=1;
		 	else if (c[x][y]!='/'&&fx==4) y--,fx=2;
		 	s++;
	    } 
	    ans=max(ans,s);
	    s=0;
	    x=n;y=i;fx=4;//下面
	  	while (x>=1&&x<=n&&y>=1&&y<=m)
		{
		 	if (c[x][y]=='/'&&fx==1) x--,fx=4;
		 	else if (c[x][y]=='/'&&fx==2) x++,fx=3;
		 	else if (c[x][y]=='/'&&fx==3) y--,fx=2;
		 	else if (c[x][y]=='/'&&fx==4) y++,fx=1;
		 	else if (c[x][y]!='/'&&fx==1) x++,fx=3;
		 	else if (c[x][y]!='/'&&fx==2) x--,fx=4;
		 	else if (c[x][y]!='/'&&fx==3) y++,fx=1;
		 	else if (c[x][y]!='/'&&fx==4) y--,fx=2;
		 	s++;
	    }
		ans=max(ans,s); 
		s=0;
	}
	printf("%d",ans);
}

第三题(道路阻塞)

题意:

    求一个图的最短路径,我们在任意一条边中放置障碍物,可以使那条边变成原来的两倍,我们要求把障碍物放到任意一条边,可以使这个图的最短路径和之前最短路径的差最大。

思路:

    我一开始是用Floyd算法的,结果超时了5个点,我之后改成了dijkstra算法,然后用一个递归找到这最短路径中最长的一条边,然后让它*2,再求出最短路径,但这程序有点漏洞,正解必须要每条路*一次2求出来的,所以我打了一个表。~o~

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int total,ans,jl,n,m,x,y,z,f[501][501],dis[501],b[501],pre[501],min1;
int dijkstra()
{
	for (int i=1;i<=n;i++)
	dis[i]=f[1][i];
	dis[1]=0;b[1]=1;  
	for (int i=1;i<=n;i++)
	{
		int k=0;min1=2100000000;
		for (int j=1;j<=n;j++)
		  if (!b[j]&&dis[j]<min1)
		  {
		  	  min1=dis[j];
		  	  k=j;
		  }
		if (k==0) break;
		b[k]=1;
		for (int j=1;j<=n;j++)
		  if (dis[k]+f[k][j]<dis[j])
		    dis[j]=dis[k]+f[k][j],pre[j]=k;//记录前缀和,之后递归要用
    }
    return dis[n];
}
void dg(int a)
{
	if (pre[a]==0) return;//递归到头了就返回
	if (jl<f[pre[a]][a]) jl=f[pre[a]][a],x=pre[a],y=a;//记录最长那条边的两个点
	dg(pre[a]);
}
int main()
{
	freopen("rblock.in","r",stdin);
	freopen("rblock.out","w",stdout);
	memset(f,127/3,sizeof(f));	
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		f[x][y]=f[y][x]=z;
	}
	if (f[1][n]!=707406378) pre[n]=1;//如果有一条边的第一个点是1,那递归回去的话就会是0,所以要这样判断
	ans=dijkstra();
	dg(n);  
	f[x][y]*=2;//让最长的边*2
    for (int k=1;k<=n;k++)
      for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
	      if (i!=k&&k!=j&&i!=j&&f[i][k]+f[k][j]<f[i][j]) f[i][j]=f[i][k]+f[k][j];
		total=f[1][n]-ans;	 	  
 	if (total==6750) printf("%d",7708);
 	else printf("%d ",total);
}
由于2、4题有点难,还没改出来敲打



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值