第1部分 基础算法(提高篇)--第4章 广搜的优化技巧1448:【例题1】电路维修

1448:【例题1】电路维修

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 991 通过数: 304
【题目描述】
译自 BalticOI 2011 Day1 T3「Switch the Lamp On」

有一种正方形的电路元件,在它的两组相对顶点中,有一组会用导线连接起来,另一组则不会。

有 N×M 个这样的元件,你想将其排列成 N 行 M 列放在电路板上。电路板的左上角连接电源,右下角连接灯泡。
在这里插入图片描述

试求:至少要旋转多少个正方形元件才能让电源与灯泡连通,若无解则输出 NO SOLUTION。

Casper is designing an electronic circuit on a N×M rectangular grid plate. There are N×M square tiles that are aligned to the grid on the plate. Two (out of four) opposite corners of each tile are connected by a wire.

A power source is connected to the top left corner of the plate. A lamp is connected to the bottom right corner of the plate. The lamp is on only if there is a path of wires connecting power source to lamp. In order to switch the lamp on, any number of tiles can be turned by

90° (in both directions).

In the picture above the lamp is off. If any one of the tiles in the second column from the right is turned by 90° , power source and lamp get connected, and the lamp is on.

Write a program to find out the minimal number of tiles that have to be turned by 90° to switch the lamp on.

【输入】
有多组测试数据。

第一行为测试数据组数,以下每组测试数据描述为:

第一行有两个整数 N 和 M。

在接下来的 N 行中,每行有 M 个字符。每个字符均为 “” 或 “/”,表示正方形元件上导线的连接方向。

The first line of input contains two integer numbers N and M, the dimensions of the plate. In each of the following N lines there are M symbols – either \ or / – which indicate the direction of the wire connecting the opposite vertices of the corresponding tile.

【输出】
每组测试数据输出描述:

输出共一行,若有解则输出一个整数,表示至少要旋转多少个正方形元件才能让电源与灯泡连通;若无解则输出 NO SOLUTION。

There must be exactly one line of output. If it is possible to switch the lamp on, this line must contain only one integer number: the minimal number of tiles that have to be turned to switch on the lamp. If it is not possible, output the string: NO SOLUTION

【输入样例】
1
3 5
\/\
\///
/\\
【输出样例】
1
【提示】
对于 40% 的数据,1≤N≤4,1≤M≤5。

对于所有数据,1≤N,M≤500。


思路:任意一根电路,它只有两种状态:
连着右上和左下
连着左下和右上
在这里插入图片描述
每条电线可以花费1的代价从一种状态改变为另外一种状态,那么我们可以对于已经连着的两点连一条权为0的边,没连着的连一条花费为1的边,求出从左上角到右下角的最短路即可。
spfa的SLF优化就是small label first 优化,当加入一个新点v的时候如果此时的dis[v]比队首dis[q.front()]还要小的话,就把v点加入到队首,否则把他加入到队尾,因为先扩展最小的点可以尽量使程序尽早的结束,一种方法可以用模拟队列,head,tail,但是由于不知道q的数组开多大,所有用双端队列dequeq更好些.

#include<cstdio>
#include<queue>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
 
int n,m;
 
const int MAXN = 251005;
 
struct edge{
    int u,v,w,nxt;
}e[MAXN<<2];int head[MAXN];int cnt = 0;int ed;int dis[MAXN];bool vis[MAXN];char c[505];
 
inline void add(int u,int v,int w){
    e[++cnt].u = u;e[cnt].v = v;e[cnt].w = w;e[cnt].nxt = head[u];head[u] = cnt;
}
 
deque<int>q;
inline void spfa(){
    q.push_back(1);
    memset(vis,0,sizeof vis);
    memset(dis,inf,sizeof dis);
    dis[1] = 0;
    
    while(!q.empty()){
        int u = q.front();q.pop_front();vis[u] = 0;
        for(int i=head[u];i;i=e[i].nxt){
            int v = e[i].v;
            if(dis[v] > dis[u] + e[i].w){
                dis[v] = dis[u] +e[i].w;
                if(!vis[v]){
                    vis[v] = 1;
                    if(e[i].w == 0) q.push_front(v);
                    else q.push_back(v);
                }
            }
        }
    }
    
    printf("%d\n",dis[ed]);
}
 
int main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        memset(head,0,sizeof head);cnt = 0;
        for(int i=1;i<=n;++i){
            scanf("%s",c+1);
            for(int j=1;j<=m;++j){
                if(c[j] == '/'){
                    add(j+1+(i-1)*(m+1) , j+i*(m+1) , 0);
                    add(j+i*(m+1) , j+1+(i-1)*(m+1) , 0);
                    add(j+(i-1)*(m+1) , j+1+i*(m+1) , 1);
                    add(j+1+i*(m+1) , j+(i-1)*(m+1) , 1);
                    
                }
                else{
                    add(j+1+(i-1)*(m+1) , j+i*(m+1) , 1);
                    add(j+i*(m+1) , j+1+(i-1)*(m+1) , 1);
                    add(j+(i-1)*(m+1) , j+1+i*(m+1) , 0);
                    add(j+1+i*(m+1) , j+(i-1)*(m+1) , 0);
                }
            }
        }
        if((n+m)%2) {puts("NO SOLUTION");continue;}
        ed = (n + 1) * (m + 1);
        spfa();
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章