sdu data structures project oil network

sdu数据结构可是的石油网络题
运用剪枝的算法,方法原创。
剪枝思路有4个
1.完全没必要放的点。(出度为0的点)
2.必须要放的点。(父节点到其的最短边加上该店到其子节点的最大边的距离大于p_max也就是最大压力值的点),一般这个就可以确定百分之八十的节点了。
3.如果一个放置方案不成立,那么这个放置方案的子集也不成立,不需要在检查这些情况。(比如一个放了k个节点的方案不成立,那么可以直接推理出有2^k-1种其他方案不成立,需要额外的空间记录,相当于空间换时间)。
4.放5个的情况成立,那么再产生放五个,六个七个的方案就直接枪毙,不用看。(最好想,也是性能提升最大的剪枝)

本来还想做二分,但是感觉比较麻烦。
代码如下,用vs编译好像会出错,我用的c## odeblocks

#include<vector>
#include<iostream>
#include<set>
#include<string.h>
#include<queue>
#include<math.h>
#define MY_MAX 1000 //此值不能过小
using namespace std;
int final_ans=MY_MAX;//先给予一个极大值
bool record[1000];
struct booster_map
{
    public:
    int booster_num;
    bool* bst_map;
    booster_map(int n){
        bst_map=new bool[n+1];
    }
    booster_map(){

    }
};
void updatefailure(int x,int cur_num,int cur_weight)
{
    ;
}
class my_graph
{
    public:
    int p_max;
    int num_v;
    int num_e;
    int source=1;
    bool* place_map;
    int** edges;
    int** longest;
    int** short_dis;//存储floyd结果
    bool* must_none;//必须不能放置的节点,不考虑源点1
    bool* must_place;//必须放置的节点位置,同样不考虑源点1
    int least_place;
    int least_dont_place;
    int* indegree;//
    int* outdegree;
    int * pre; //当前各个节点的pre值
    int min_ac;//当前最小的放置节点个数,如果生成数比这个大可以放弃
    my_graph(int n,int m,int p){
        min_ac=num_v-1;//如果除源点外全部放置,一定能够成立
        num_v=n;
        num_e=m;
        p_max=p;
        least_place=least_dont_place=0;
        place_map=new bool[100];
        indegree=new int[n+1];
        outdegree=new int[n+1];
        must_none=new bool[n+1];
        must_place=new bool[n+1];
        memset(place_map,false,100);
        edges=new int* [n+1];
        longest=new int*[n+1];
        short_dis=new int* [n+1];
        pre=new int [n+1];
        for(int i=1;i<=n;i++){
            must_none[i]=false;
            must_place[i]=false;//初始状态认为都有可能放置或不放置
            indegree[i]=outdegree[i]=0;
            edges[i]=new int[n+1];
            longest[i]=new int[n+1];
            short_dis[i]=new int[n+1];
            pre[i]=-1;//-1表示未到达,0表示刚好压力能到达
        }
        pre[1]=p_max;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                edges[i][j]=MY_MAX;//初始化为无穷
                short_dis[i][j]=MY_MAX;
                longest[i][j]=-1;//-1初始化表示不存在
            }
        }
    }
    vector<booster_map> all_maps;
    set<int> new_activited;
    int generate_map(int x);//生成穷举列表
    void pre_set();
    void assess();
    void floyd();
    void test_floyd();
    void first_pre_generate_from_source();
    void genrate_from_activited();//根据new_activated的元素更新pre值,假设有上一轮被激活的,并将这一轮新激活的节点更新
    bool check_all_points();//检查是否所有点都已经到达
    bool check_longest();
    void  print_pre();
    void print_longest();
    void cal_empty_node();//计算必须放置为空的位置
    void cal_essential();//记录必须放置放大器的节点
    bool check_cur_map();//检查当前放置序列是否满足要求(一定不能放的位置和一定放的位置的放置情况
    void generate_all_maps();//将生成的全部符合要求的穷举列表存入vector中
    bool erase_unnecessary_edge();//删去不必要的最长边

};
void my_graph::test_floyd()
{
    for(int i=1;i<=num_v;i++){
        for(int j=1;j<=num_v;j++){
            cout<<edges[i][j]<<"     ";
        }
        cout<<"\n";
    }
    cout<<"\n";
    for(int i=1;i<=num_v;i++){
        for(int j=1;j<=num_v;j++){
            cout<<short_dis[i][j]<<"     ";
        }
        cout<<"\n";
    }
}
void my_graph::pre_set()
{
    for(int i=1;i<=num_v;i++){
        pre[i]=-1;
    }
    pre[1]=p_max;
    new_activited.clear();
}

void my_graph::floyd()
{
    for(int i=1;i<=num_v;i++){
        short_dis[i][i]=0;//每个点到自身距离为0
    }


    for(int k=1;k<=num_v;k++)
        for(int i=1;i<=num_v;i++){
            for(int j=1;j<=num_v;j++){

                if(short_dis[i][j]>short_dis[i][k]+short_dis[k][j]){
                    short_dis[i][j]=short_dis[i][k]+short_dis[k][j];
                }
            }
        }
}
int my_graph::generate_map(int x)//生成穷举列表,返回放置放大器的个数
{
  //  vector<int> debug;
    int res=0;
    for(int i=2;i<=num_v;i++){//第一个点一定是true 源点
        place_map[i]=x%2;
        if(place_map[i]==true){
          //  debug.push_back(i);
            res++;
        }
        x=x/2;
    }
    /*
    cout<<"放置放大器为:";
    for(int i=0;i<debug.size();i++){
        cout<<debug[i]<<" ";
    }
    cout<<"\n";
    */
    return res;
}
void my_graph::first_pre_generate_from_source()//从源点开始更新pre,且将激活的booster存入activited
{
   // vector<int> debug;
    int * row=short_dis[1];//第一行的弗洛伊德结果
    for(int i=2;i<=num_v;i++){//source so begin from 2
        if(row[i]<=p_max){
            pre[i]=p_max-row[i];//假如距离小于等于压力,更新pre值
            if(place_map[i]==true){//假如此处放置booster,则激活
                new_activited.insert(i);
               // debug.push_back(i);
            }
        }
    }
    /*
    cout<<"从源点1开始激活的放大器为:";
    for(int i=0;i<debug.size();i++){
        cout<<debug[i]<<" ";
    }
    cout<<"\n";
    */
}
void my_graph::genrate_from_activited()//根据new_activated的元素更新pre值,假设有上一轮被激活的,并将这一轮新激活的节点更新
{
    bool have_entered[100];
    memset(have_entered,false,100);
    queue<int> q;
    for(auto it=new_activited.begin();it!=new_activited.end();it++){//把被源点激活的函数放入队列
        int cur=*it;
        q.push(cur);
        have_entered[cur]=true;//表示是否进入队列
   }
   while(q.empty()==false)
    {
            int cur_s=q.front();
            q.pop();
            int* row=short_dis[cur_s];
            for(int i=1;i<=num_v;i++){
                if(i==cur_s){
                    pre[i]=p_max;
                    continue;
                }
                if(row[i]<=p_max){
                    pre[i]=max(pre[i],p_max-row[i]);//注意,此时其他源点的造成的pre值可能比当前值大
                    if(place_map[i]==true&&have_entered[i]==false){//假如二进制生成图允许,且这一放大器未被使用过,加入队列
                        q.push(i);
                        have_entered[i]=true;
                    }
                }
            }

    }
    //cout<<"endprocess\n";
}
bool my_graph::check_all_points()//检查是否所有点都已经到达
{
    for(int i=2;i<=num_v;i++){
        if(pre[i]==-1){
            return false;
        }
    }
    return true;
}
bool my_graph::check_longest()
{

    for(int i=1;i<=num_v;i++){
        for(int j=1;j<=num_v;j++){
            if(i==j){
                continue;
            }
            if(longest[i][j]==-1){
                continue;
            }
            if(pre[i]<longest[i][j]){//此时源点信号强度小于最长边长度

                return false;
            }
        }
    }
    return true;
}
void my_graph::print_pre()
{
    for(int i=1;i<=num_v;i++){
        cout<<"node"<<i<<" "<<pre[i]<<" ";
    }
    cout<<"\n";
}
void my_graph::print_longest()
{
    for(int i=1;i<=num_v;i++){
        for(int j=1;j<=num_v;j++){
            cout<<longest[i][j]<<" ";
        }
        cout<<"\n";
    }
}
void my_graph::cal_empty_node()//计算必须放置为空的位置
{
    //vector<int> debug;
    for(int i=2;i<=num_v;i++){
        if(outdegree[i]==0){
            must_none[i]=true;
            least_dont_place++;
           // debug.push_back(i);
        }
    }
    /*
    cout<<"完全没必要放置的节点为:";
    for(int i=0;i<debug.size();i++){
        cout<<debug[i]<<" ";
    }
    cout<<"\n";
    */

}
bool my_graph::erase_unnecessary_edge()//删去不必要的最长边
{
    int* l_row=longest[1];//以源点为起点的最长边
    for(int i=2;i<=num_v;i++){
        if(l_row[i]==-1){
            continue;//不存在对应边
        }
        if(l_row[i]<=p_max){
            l_row[i]=-1;
        }
    }
}
void my_graph::cal_essential()//记录必须放置放大器的节点
{
    //vector<int> debug;
    for(int i=2;i<=num_v;i++){
        if(must_none[i]==true){
            continue;//已经计算过这里肯定不用放
        }
        int min_in_edge=MY_MAX;//记录最短入边
        for(int j=1;j<=num_v;j++){
            min_in_edge=min(min_in_edge,edges[j][i]);//至少有一个点指向当前节点,因此min_in_edge不为MY_MAX
        }
        int max_out_edge=0;
        for(int j=2;j<=num_v;j++){ //肯定不会有指向1的边
            max_out_edge=max(max_out_edge,longest[i][j]);
        }
        if(p_max<min_in_edge+max_out_edge){//此位置必须放置放大器
            must_place[i]=true;
           // debug.push_back(i);
            least_place++;
        }
    }
    /*
    cout<<"必须放置的节点为:";
    for(int i=0;i<debug.size();i++){
        cout<<debug[i]<<" ";
    }
    cout<<"\n";
    */
}
bool my_graph::check_cur_map()//检查当前放置序列是否满足要求(一定不能放的位置和一定放的位置的放置情况
{
    for(int i=2;i<=num_v;i++){
        if(place_map[i]==true){
            if(must_none[i]==true){
                return false;
            }
        }
        if(place_map[i]==false){
            if(must_place[i]==true){
                return false;
            }
        }
    }
    return true;
}
void my_graph::generate_all_maps()//将生成的全部符合要求的穷举列表存入vector中,   等会再写
{
    int max_num=pow(2,num_v-1)-1;
    for(int i=0;i<=max_num;i++){
        int cur=i;
        booster_map* new_map=new booster_map();
        for(int j=2;j<=num_v;j++){
            new_map->bst_map[j]=cur%2;
            if(new_map->bst_map[j]==true){
                new_map->booster_num++;
            }
        }
        if(new_map->booster_num>num_v-least_dont_place-1||new_map->booster_num<least_place){
            delete new_map;//
        }
        else{
            all_maps.push_back(*new_map);
        }
    }
}
bool* failure;//失败者图
void update_failure(int x,int cur_num,int cur_weight)
{
    cout<<"stuck"<<x;
    if(x==0){
        failure[cur_num]=true;
        return;
    }
    if(x%2==0){
        x=x/2;
        update_failure(x,cur_num,2*cur_weight);
        return ;
    }
    else{
        x=x/2;
        update_failure(x,cur_num+cur_weight,2*cur_weight);//当前位置取1
        update_failure(x,cur_num,2*cur_weight);//当前位置取0
        return;
    }
    return;
}
void record_map(my_graph& g)//将放大器图位置保存
{
    for(int i=2;i<=g.num_v;i++){
        record[i]=g.place_map[i];
    }
}
int show_pre[100];
void record_pre(my_graph& g){
    for(int i=2;i<=g.num_v;i++){
        show_pre[i]=g.pre[i];
    }
}
int main()
{
    int n,m,l;
  //  ios::sync_with_stdio(false);
   、、 freopen("input1.in","r",stdin);
    cin>>n>>m>>l;
    my_graph graph(n,m,l);
    int x,y,c;
    for(int i=0;i<m;i++){
        cin>>x>>y>>c;
        graph.indegree[y]++;
        graph.outdegree[x]++;
        graph.longest[x][y]=max(graph.longest[x][y],c);//记录最长边
        if(graph.edges[x][y]>c){
            graph.edges[x][y]=c;
            graph.short_dis[x][y]=c;
        }
    }
    graph.floyd();
    graph.cal_empty_node();
    graph.cal_essential();
    int lo_bound=graph.least_place;//二分下界
    int hi_bound=n-graph.least_dont_place-1;//二分上界
    int max_genrate=pow(2,n-1)-1;
    int generate_num=max_genrate;
    failure=new bool[1000000];//!!!!数组开小了会溢出
    memset(failure,0,1000000);
    memset(record,0,1000);
  //  cout<<"gen"<<generate_num;
    int mid_begin=max_genrate/2;

    for(;generate_num>=0;generate_num--){
        int temp=graph.generate_map(generate_num);//生成当前图放置
        if(temp>=final_ans){//当前地图放置数量比最目前最小数量大,直接跳过
            continue;
        }
        if(graph.check_cur_map()==false){//当前放置位置一定不对(有多放或少放的
            continue;
        }
        if(failure[generate_num]==true){//当前放置为之前失败放置的子集
            continue;
        }
        graph.pre_set(); //初始化
        graph.first_pre_generate_from_source();//从源点激活
        graph.genrate_from_activited(); //依次激活其他点
        if(graph.check_all_points()==true&&graph.check_longest()==true){
         //   cout<<"this plan is accessble\n";
           // graph.print_pre();
          // graph.print_longest();
            final_ans=min(final_ans,temp);
            record_map(graph);
            record_pre(graph);
        }else{
            update_failure(generate_num,0,1);
        }
       // cout<<"\n";
    }
    cout<<"num of booster is "<<final_ans<<"\n";
   // cout<<final_ans;
    cout<<"放大器位置为:";
    for(int i=2;i<=n;i++){
        if(record[i]==true){
            cout<<"node"<<i<<" ";
        }
    }
    cout<<"\n";
    show_pre[1]=l;
    cout<<"各节点压力值为:\n";
    for(int i=1;i<=n;i++){
        cout<<"node"<<i<<":"<<show_pre[i]<<"\n";
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值