luogu P4667 [BalticOI 2011] Switch the Lamp On (Day1)

P4667 [BalticOI 2011] Switch the Lamp On (Day1)

题目描述

Casper 在一个 \(N\times M\) 的电路板上设计电路。有一种正方形的电路元件,在它的两组相对顶点中,有一组会用导线连接起来,另一组则不会。有 \(N\times M\) 个这样的元件,你想将其排列成 \(N\) 行,每行 \(M\) 个。 电源连接到板的左上角。灯连接到板的右下角。只有在电源和灯之间有一条电线连接的情况下,灯才会亮着。为了打开灯,任何数量的电路元件都可以转动 90°(两个方向)。

在上面的图片中,灯是关着的。如果从右往左数第二列的任何一个电路元件被旋转 90°,电源和灯都会连接,灯被打开。现在请你编写一个程序,求出最小需要旋转多少电路元件。

输入格式

输入的第一行包含两个整数 \(N\)\(M\),表示电路板的尺寸。 在以下 \(N\) 行中,每一行有 \(M\) 个符号 \/,表示连接对应电路元件对角线的导线的方向。

输出格式

如果可以打开灯,那么输出只包含一个整数,表示最少转动电路元件的数量。

如果不可能打开灯,输出 NO SOLUTION

输入输出样例 #1

输入 #1

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

输出 #1

1

说明/提示

对于 \(40\%\) 的数据,\(1 \le N \le 4\)\(1 \le M \le 5\)

对于所有数据,\(1 \le N,M \le 500\)

思路概述

如果把给出的线路看作图就好办了。

容易发现题目给出的信息是边,那么“节点”就在每条边所在“正方形”的四角。

因为答案是“要扭动多少条边”,所以定义:如果两条边直接相连,那么建立的边的边权为 \(0\) ,否则为 \(1\)

最后很简单,直接跑最短路。

难点在于细节很多,例如:得到点的编号,点到边的编号转化,等等。要细心。

代码示例

#include <bits/stdc++.h>
using namespace std;
const int N=2010;
const int M=2001010;
typedef long long ll;
struct edge {
	int x,y,val;
};
bool cmp(const edge &a,const edge &b) {
	return a.val<b.val;
}
int n,tot,x,y,cnt;
ll ans;
edge ed[M];
int fa[N];
int find(int u) {
	if(fa[u]==u) return u;
	else return fa[u]=find(fa[u]);
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
		for(int j=i;j<=n;j++) {
			cin>>x;
			ed[++tot].x=i-1;
			ed[tot].y=j;
			ed[tot].val=x;
		}
	sort(ed+1,ed+1+tot,cmp);
	for(int i=0;i<=n;i++) fa[i]=i;
	for(int i=1;i<=tot && cnt<n;i++) {
		x=ed[i].x; y=ed[i].y;
		if(find(x)!=find(y)) {
			fa[find(x)]=find(y);
			ans+=(ll)ed[i].val;
			cnt++;
		}
	} 
	cout<<ans;
	return 0;
}

写在后面

请观众老爷们给我一个关注吧~


posted @ 2026-05-02 16:13  naijil  阅读(10)  评论(0)    收藏  举报