POJ电路维修

电路维修

题目:

提交链接:https://www.luogu.com.cn/problem/T282123

题目背景

达达是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女翰翰,从而被收留在地球上。

题目描述

翰翰的家里有一辆飞行车。 有一天飞行车的电路板突然出现了故障,导致无法启动。 电路板的整体结构是一个 R 行 C 列的网格(R,C≤500),如下图所示。

在这里插入图片描述

每个格点都是电线的接点,每个格子都包含一个电子元件。 电子元件的主要部分是一个可旋转的、连接一条对角线上的两个接点的短电缆。 在旋转之后,它就可以连接另一条对角线的两个接点。 电路板左上角的接点接入直流电源,右下角的接点接入飞行车的发动装置。 达达发现因为某些元件的方向不小心发生了改变,电路板可能处于断路的状态。 她准备通过计算,旋转最少数量的元件,使电源与发动装置通过若干条短缆相连。 不过,电路的规模实在是太大了,达达并不擅长编程,希望你能够帮她解决这个 问题。

在这里插入图片描述

输入格式

输入文件包含多组测试数据。 第一行包含一个整数 T,表示测试数据的数目。 对于每组测试数据,第一行包含正整数 R 和 C,表示电路板的行数和列数。 之后 R 行,每行 C 个字符,字符是" / “和” \ "中的一个,表示标准件的方向。

输出格式

对于每组测试数据,在单独的一行输出一个正整数,表示所需的缩小旋转次数。 如果无论怎样都不能使得电源和发动机之间连通,输出 NO SOLUTION

输入输出样例

输入 #1

1
3 5
\\/\\
\\///
/\\\\

输出 #1

1

说明/提示

1≤R,C≤500 , 1≤T≤5

解析:

这里是算能到最后元件的旋转的次数,即从(1,1)到(r+1,c+1)联通所需要的旋转次数

最先能想到的是搜索~~(但是我没有写~~

然后我们再来看,如果两个点最先开始是联通的那通过的时候的代价就是0,如果不连通通过的代价就是1(因为再转一次就会恢复,就是不优的)。

这样一看像不像两点之间的用边权为0或1连接起来的图。

那从起点到终点的最小代价就是在起点到终点求的最短路。当然因为边权只有0和1你可以写一个双边队列。

注意写最短路时最好用Dijkstra,这道题是稠密图用spfa会被卡。这里有多组数据,所以要注意初始化

还有就是要从0开始建边,为什么不从1开始?(因为我写挂了

浅附一个spfa(只有70分)

//电路维修
#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<queue>
using namespace std;
const int MAXN = 2500005;
const int inf = 0x3f3f3f3f;

struct Edge
{
	int u,v,w,nex;
}E[MAXN<<1];

int n,t,r,c,dis[MAXN];
char di;
bool vis[MAXN]; 

int head[MAXN],tot;

inline void in()
{
	memset(vis,0,sizeof(vis));
	memset(dis,inf,sizeof(dis));
	memset(head,0,sizeof(head));
}

inline void Add_Edge(int u,int v,int w)
{
	E[tot].u=u,
	E[tot].v=v,
	E[tot].w=w,
	E[tot].nex=head[u],
	head[u]=tot++;
}

inline int read()
{
	int k=0,f=1;
	char c=getchar();
	while(!isdigit(c))
	{
		if(c=='-')	f=-1;
		c=getchar();
	}
	while(isdigit(c))
	{
		k=k*10+(c-48);
		c=getchar();
	}
	return f*k;
}

inline void spfa(int u)
{
	int i,v,w;
	vis[u]=true,dis[u]=0;
	queue<int>q;
	q.push(u);
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		vis[u]=false;
		for(i=head[u];i;i=E[i].nex)
		{
			v=E[i].v,w=E[i].w;
			if(dis[v]>dis[u]+w)
			{
				dis[v]=dis[u]+w;
				if(!vis[v])
				{
					q.push(v);
					vis[v]=true;
				}
			}
		}
	}
}

int main()
{
	t=read();
	int i,j,ans;
	while(t--)
	{
		r=read(),c=read(),ans=0,tot=0,++c;
		in();
		
		for(i=0;i<r;++i)
			for(j=0;j<c-1;++j)
			{
//				scanf("%c",&di[i][j]);
				cin >> di;
				if(di=='/')
				{
					Add_Edge(i*c+j+1,(i+1)*c+j,0);
					Add_Edge((i+1)*c+j,i*c+j+1,0);
					Add_Edge(i*c+j,(i+1)*c+j+1,1);
					Add_Edge((i+1)*c+j+1,i*c+j,1);
				}
				else
				{
					Add_Edge(i*c+j+1,(i+1)*c+j,1);
					Add_Edge((i+1)*c+j,i*c+j+1,1);
					Add_Edge(i*c+j,(i+1)*c+j+1,0);
					Add_Edge((i+1)*c+j+1,i*c+j,0);
				}
			}
			
		if((r+c-1)&1)
		{
			printf("NO SOLUTION\n");
			continue;
		}
		
		spfa(0),++r;
		printf("%d\n",dis[r*c-1]);
	}
	return 0;
}

AC代码

//电路维修
#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<queue>
using namespace std;
const int MAXN = 2500005;
const int inf = 0x3f3f3f3f;

struct Edge
{
	int u,v,w,nex;
}E[MAXN<<1];

int n,t,r,c,dis[MAXN],pre[MAXN];
char di;
bool vis[MAXN]; 

int head[MAXN],tot;

inline void in()
{
	memset(vis,0,sizeof(vis));
	memset(dis,inf,sizeof(dis));
	memset(head,0,sizeof(head));
}

inline void Add_Edge(int u,int v,int w)
{
	E[tot].u=u,
	E[tot].v=v,
	E[tot].w=w,
	E[tot].nex=head[u],
	head[u]=tot++;
}

inline int read()
{
	int k=0,f=1;
	char c=getchar();
	while(!isdigit(c))
	{
		if(c=='-')	f=-1;
		c=getchar();
	}
	while(isdigit(c))
	{
		k=k*10+(c-48);
		c=getchar();
	}
	return f*k;
}

struct Node
{
	int num;
	int val;
};
priority_queue<Node>q;
bool operator<(Node a,Node b)
{
	return a.val>b.val;
}

int main()
{
//	freopen("cir.in","r",stdin);
//	freopen("cir.out","w",stdout);
	t=read();
	int i,j,ans,u,v,w;
	while(t--)
	{
		r=read(),c=read(),ans=0,tot=0,++c;
		in();
		
		for(i=0;i<r;++i)
			for(j=0;j<c-1;++j)
			{
//				scanf("%c",&di[i][j]);
				cin >> di;
				if(di=='/')
				{
					Add_Edge(i*c+j+1,(i+1)*c+j,0);
					Add_Edge((i+1)*c+j,i*c+j+1,0);
					Add_Edge(i*c+j,(i+1)*c+j+1,1);
					Add_Edge((i+1)*c+j+1,i*c+j,1);
				}
				else
				{
					Add_Edge(i*c+j+1,(i+1)*c+j,1);
					Add_Edge((i+1)*c+j,i*c+j+1,1);
					Add_Edge(i*c+j,(i+1)*c+j+1,0);
					Add_Edge((i+1)*c+j+1,i*c+j,0);
				}
			}
			
		if((r+c-1)&1)
		{
			printf("NO SOLUTION\n");
			continue;
		}
		++r;
		dis[0]=0;
		Node s;
		s.num=0,s.val=0,q.push(s);
		for(i=0;i<=r*c&&!q.empty();++i)
		{
			do
			{
				s=q.top();
				q.pop();
			}while(vis[s.num]&&!q.empty());
			u=s.num,vis[u]=1;
			for(j=head[u];j;j=E[j].nex)
			{
				v=E[j].v,w=E[j].w;
				if(dis[v]>dis[u]+w)
				{
					dis[v]=dis[u]+w;
					pre[v]=u;
					Node sv;
					sv.num=v,sv.val=dis[v];
					q.push(sv);
				}
			}
		}
		
		printf("%d\n",dis[r*c-1]);
	}
	return 0;
}

完结撒花✿✿ヽ(°▽°)ノ✿
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值