一道BFS作业题

今天算法设计与分析课上布置了一道BFS,感觉还是挺有意思的。

估摸着放到CF上这道题应该能有1700左右吧qwq

拿来和大家分享一下

题目大家自己看一看,我来解释一下样例。

样例输入,3就代表有3个元件,第二行表示元件1和2之间要接2根线,元件1和3之间要接3根线,第三行表示元件2和3之间要接3根线。

样例输出,10代表最小成本是10(可以算,成本是1*3+2*2+1*3=10, 可以证明这是最小的),第二行表示这种可以达到最小成本的布线方式。

这题怎么做呢?

我们的node(答案集)里面应该包括三个东西,即现在已经有的点,现在已经有的点所拥有的布线成本,和这几个点的位置分布(数组形式)。既然要用优先队列,那我们就得先重载一下小于运算符。

这道题应该是一个搜索题,我们使用BFS进行 ,由于数据量为20且要求排列,复杂度可能高达阶乘级别,这样的复杂度是难以通过的。我们需要进行剪枝,具体的剪枝方案如下:

①当正在扩展的节点的成本已经超过目前的最优解,那么就直接break掉(即不把这个扩展节点扔进队列)

②当当前节点的成本已经超过了目前的最优解,说明下面无论如何放置成本都不会更低,可以直接break出循环。

这样的话会让复杂度得到一个较大的缓解。可以在比较短的时间内通过这道题。

其实有一说一,不是很能理解为什么这题一定要用优先队列来做。普通队列毕竟少一个log的复杂度。

不过这样优先拿成本小的情况出来处理,确实会导致更多的剪枝操作。可能优先队列的平均复杂度更低吧()

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(x,y) memset(x,y,sizeof(x))
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define db double
#define inf 0x3f3f3f3f
bool ispow(ll n){return (n&(n-1))==0;}
#define lowbit(x) (x&(-x))
const int mod=1e9+7;
int con[25][25];
int anselem[25];
int n;
struct node{
    int num;
    int cost;
    int member[25];
    bool operator<(const node& a)const{
        return cost<a.cost;
    }
}a[25];

int cal(node nn,int curnum){
    int res=0;
    for(int i=1;i<=curnum-1;i++){
        for(int j=i+1;j<=curnum;j++) res+=(abs(j-i)*con[nn.member[i]][nn.member[j]]);
    }
    return res;
}


int solve(){
    priority_queue<node>q;
    node cur;
    cur.num=0,cur.cost=0;
    for(int i=1;i<=n;i++) cur.member[i]=i;
    q.push(cur);
    int minn=inf;
    while(!q.empty()){
      cur=q.top();
        q.pop();
        if(cur.cost>=minn) break;
        if(cur.num==n-1){
            int temp=cal(cur,n);
            if(temp<minn){
                minn=temp;
                for(int i=1;i<=n;i++) anselem[i]=cur.member[i];
            }
        }
        else{
            for(int i=cur.num+1;i<=n;i++){
                node nxt;
                nxt.num=cur.num+1;
                for(int j=1;j<=n;j++) nxt.member[j]=cur.member[j];
                nxt.member[nxt.num]=cur.member[i];
                nxt.member[i]=cur.member[nxt.num];
                nxt.cost=cal(nxt,nxt.num);
                if(nxt.cost<minn) q.push(nxt);
            }
        }
    }
    return minn;
}

int main()
{
    fast;
    cin>>n;
    for(int i=1;i<=n-1;i++)
        for(int j=i+1;j<=n;j++) 
        {
            int r;
            cin>>r;
            con[i][j]=r;
            con[j][i]=r;
        }
    int ans=solve();
    cout<<ans<<'\n';
//    node r;
//    for(int i=1;i<=n;i++) r.member[i]=anselem[i];
//    cout<<cal(r,n)<<'\n';
    for(int i=1;i<=n;i++) cout<<anselem[i]<<' ';
    return 0;
}

老师当时给的样例不完整,然后我就去到处找样例数据。最后竟然还真在一个博主的博客下面找到了这组数据

Reference:https://blog.csdn.net/ioio_/article/details/81176845 

大家可以拿数据自己测试。(上面倒数后几行被注释掉的代码,就是相当于一个spj,可以拿那个检查自己的排列是否正确)

[Test #1]
Input:
3
2 3
3

Output:
10
1 3 2

[Test #2]
Input:
9
18 1 10 18 10 14 8 4 
17 8 10 16 5 12 2 
11 0 7 14 19 16 
6 17 2 18 18 
6 0 8 9 
7 11 14 
13 6 
17


Output:
964
2 3 8 5 1 4 9 6 7

[Test #3]
Input:
9
2 6 5 10 4 19 0 0 
6 19 7 12 5 1 18 
12 8 14 0 10 13 
1 5 18 5 14 
7 4 17 7 
13 3 7 
18 14 
5

Output:
804
1 9 6 8 2 5 4 3 7

那就到这里吧,这几天要赶大作业了。

坦克大战好难啊qwqqq

猜你喜欢

转载自www.cnblogs.com/GetZero/p/12933663.html
今日推荐