洛谷P2243 电路维修

Posted Soda

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷P2243 电路维修相关的知识,希望对你有一定的参考价值。

P2243 电路维修

题目背景

Elf 是来自Gliese 星球的少女,由于偶然的原因漂流到了地球上。在她无依无靠的时候,善良的运输队员Mark 和James 收留了她。Elf 很感谢Mark和James,可是一直也没能给他们帮上什么忙。

题目描述

有一天 Mark 和James 的飞行车没有办法启动了,经过检查发现原来是电路板的故障。飞行车的电路板设计很奇葩,如下图所示:

技术分享

输入输出格式

输入格式:

 

输入文件包含多组测试数据。第一行包含一个整数T 表示测试数据的数目。

对于每组测试数据,第一行包含正整数 R 和C,表示电路板的行数和列数。

之后 R 行,每行C 个字符,字符是"/"和"\"中的一个,表示标准件的方向。

对于40% 的数据,R,C≤5。

对于 100% 的数据,R,C≤500,T≤5。

 

输出格式:

 

对于每组测试数据,在单独的一行输出一个正整数,表示所需的缩小旋转次数。

如果无论怎样都不能使得电源和发动机之间连通,输出 NO SOLUTION。

 

输入输出样例

输入样例#1:
1
3 5
\\/\\\///
/\\\
输出样例#1:
1

说明

样例的输入对应于题目描述中的情况。

只需要按照下面的方式旋转标准件,就可以使得电源和发动机之间连通。

技术分享

/*
    提交超多通过率超低的题,总而言之算法秒掉了,然而在图论上本人自带不初始化buff。
    算法:我们把可以不旋转通过的边标记为0,需要旋转的标记为1,跑一次单源最短路,从左上到右下,易发现最短距离就是需要旋转的次数。
    (我们可以看成每次要用到旋转后的边,需要耗费1的价值,最后价值总和当然就是答案。)
    我们这样想,这是个图。可以数出来,节点数应当是(R+1)*(C+1)
    建图的时候,按如下方式分配点的编号。 
    1 2 3 4 5 6
    7 8 9 10 11 12
    ...当然这是样例。我们可以发现,对于每个方格,需要标记四个点,四个点坐标可以轻易求得。
    这就是这部分的作用:
        int pos1=((i-1)*(C+1)+j); //左上
        int pos2=(i*(C+1)+j+1);      //右下 
        int pos3=((i-1)*(C+1)+j+1);  //右上 
        int pos4=(i*(C+1)+j);        //左下 
    我们确定了四个点的位置,接下来就只需要连边了。(好在这道题对于内存没限制,随便开简直爽。)
    如果‘/‘就右上到左下连边,这条边权值为0(val=0)。连边要连双向(未证实,我这么连得。)
    同时也要双向的连一条从左上到右下的边,权值为1,表示旋转后的边。
    如果是’\‘则反之。
    图建好了,对于如此稠密的图我选择heap优化的dijkstra。不清楚其他单源能否过,但多源估计过不了。
    最后答案就是1到(R+1)*(C+1)的最短路
    
    我一开始用的priority_queue<pa,vector<pa>,greater<pa> >q; T一个点,换成结构体+重载运算符A了 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define maxn 260000
int T,n,m,num,head[maxn],dis[maxn],cou;
bool vis[maxn];
struct node{
    int to,pre,v;
}e[maxn*10];
char ch[510];
void Insert(int from,int to,int v){
    e[++num].to=to;
    e[num].v=v;
    e[num].pre=head[from];
    head[from]=num;
}
int qread(){
    int i=0;
    char ch=getchar();
    while(ch<0||ch>9)ch=getchar();
    while(ch<=9&&ch>=0){i=i*10+ch-0;ch=getchar();}
    return i;
}
struct Node{
    int id,v;
    bool operator < (const Node x)const{
        return v>x.v;
    }
};
void Dij(){
    priority_queue<Node>q;
    memset(vis,0,sizeof(vis));
    memset(dis,127/3,sizeof(dis));
    dis[1]=0;
    Node cur;cur.id=1,cur.v=0;
    q.push(cur);
    while(!q.empty()){
        int point=q.top().id;q.pop();
        if(vis[point])continue;
        vis[point]=1;
        if(point==cou)return;
        for(int i=head[point];i;i=e[i].pre){
            int to=e[i].to;
            if(dis[to]>dis[point]+e[i].v){
                dis[to]=dis[point]+e[i].v;
                Node nxt;nxt.id=to,nxt.v=dis[to];
                q.push(nxt);
            }
        }
    }
}
int main(){
    freopen("Cola.txt","r",stdin);
    T=qread();
    while(T--){
        memset(head,0,sizeof(head));
        memset(e,0,sizeof(e));
        num=0;
        n=qread();m=qread();
        cou=(n+1)*(m+1);
        int a,b,c,d;
        for(int i=1;i<=n;i++){
            scanf("%s",ch+1);
            for(int j=1;j<=m;j++){
                int pos1=((i-1)*(m+1)+j);//左上 
                int pos2=(i*(m+1)+j+1);//右下 
                int pos3=((i-1)*(m+1)+j+1);//右上 
                int pos4=(i*(m+1)+j);//左下 
                if(ch[j]==\\){
                    Insert(pos1,pos2,0);Insert(pos2,pos1,0);
                    Insert(pos3,pos4,1);Insert(pos4,pos3,1);
                }
                else {
                    Insert(pos1,pos2,1);Insert(pos2,pos1,1);
                    Insert(pos3,pos4,0);Insert(pos4,pos3,0);
                }
            }
        }
        Dij();
        if(dis[cou]>=107406378)printf("NO SOLUTION\n");
        else printf("%d\n",dis[cou]);
    }
}

 

以上是关于洛谷P2243 电路维修的主要内容,如果未能解决你的问题,请参考以下文章

P2243 电路维修

luogu P2243 电路维修

维修电路

洛谷P2242 公路维修问题

Luogu_P2243 电路维修题解 双端队列bfs

洛谷 P2242 公路维修问题