codevs 1002 搭桥

codevs 1002 搭桥

  1. 刚开始看这题的时候觉得就是宽搜+并查集就可以搞定了,觉得一定可以把这题ac的。

  2. 然后从昨晚敲代码,再到今天10点敲到现在,发现有一半样例WA,实在想不出是什么情况,后来看看错误提示,发现桥的数目和长度有可能是不一样的。欸,那是什么情况呢?突然间觉得好有挫败感,所以开始研究一份看起来比较简短优美的题解吧。代码如下:

  3.    #include <algorithm>
       using namespace std;
       #define maxn 100000
       int xx[8]={0,0,1,1,1,-1,-1,-1},yy[8]={1,-1,0,1,-1,0,1,-1};
       int n,m,q[1005][1005],dad[maxn],cnt,ans,sum;
       bool map[1005][1005];
       struct node{int x,y,v;}e[maxn]; //边的结构体,v代表长度 
       bool cmp(node a,node b){return a.v<b.v;}
       int getdad(int x){return x==dad[x]?x:dad[x]=getdad(dad[x]);} //并查集find祖先 
       bool input(int x1,int y1,int x2,int y2,int t){
        if(x2<1||x2>n||y2<1||y2>m||!q[x2][y2]) //坐标不合法或者这不是个建筑物 
            return 1; //不合法 
        if(q[x1][y1]==q[x2][y2]) 
            return 0; //属于同一个建筑物 
        cnt++;
        e[cnt].x=q[x1][y1];
        e[cnt].y=q[x2][y2];
        e[cnt].v=t-1;
        return 1;
       }
       void dfs(int x,int y){
        q[x][y]=ans;
        for(int i=0;i<8;i++){
            int x0=x+xx[i],y0=y+yy[i];
            if(map[x0][y0]&&!q[x0][y0]) dfs(x0,y0);
        }
       }
       void build(int x,int y) //在(x,y)这个点上可以建的桥 
       {
        for(int i=x+1;i<=n;i++) // 下面的 
          if(!input(x,y,i,y,i-x)||!input(x,y,i,y+1,i-x)||!input(x,y,i,y-1,i-x)) break;
        for(int i=x-1;i>0;i--)  //上面的 
          if(!input(x,y,i,y,x-i)||!input(x,y,i,y+1,x-i)||!input(x,y,i,y-1,x-i)) break;
        for(int i=y+1;i<=m;i++) // 右边的 
          if(!input(x,y,x,i,i-y)||!input(x,y,x+1,i,i-y)||!input(x,y,x-1,i,i-y)) break;
        for(int i=y-1;i>0;i--) //左边的 
          if(!input(x,y,x,i,y-1)||!input(x,y,x+1,i,y-i)||!input(x,y,x-1,i,y-i)) break;  
       }
       void work1(){
           ans=0;
        for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
            if(map[i][j]&&!q[i][j]) {ans++;dfs(i,j);} //ans是联通块编号 
        cout<<ans<<endl;
       }
       void work2()
       {
    
        for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
             if(map[i][j]) build(i,j); //枚举所有可能的桥 
          sort(e+1,e+cnt+1,cmp); //sort所有的桥,长度从小到大 
          for(int i=1;i<=ans;i++) dad[i]=i;//联通快编号初始化 
          ans=0;
          for(int i=1;i<=cnt;i++)
          {
            int k=getdad(e[i].x);
            int l=getdad(e[i].y);
            if(k!=l) // 不属于同一个联通快,要用桥连接 
            {
                dad[k]=l;
                ans++;
                sum+=e[i].v;
            }
          }
          cout<<ans<<' '<<sum;
       }
    
       int main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++)
          {
            char a[maxn];
            cin>>a;
            for(int j=1;j<=m;j++)
            if(a[j-1]=='#') map[i][j]=1; //整数数组map保存下来了 
          }
        work1();
        work2();
        return 0;
       }
  4. 就是枚举出所有的边, kruskal+dfs
  5. 有种力不从心的感觉。但尽量坚持下去吧- -
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值