第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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章