第十九届黑龙江省大学生程序设计竞赛

总结:这场比赛主要是得写出F题才能跨层。五题看罚时。以后能用next_permutation就不要用dfs,dfs写得比较长,浪费时间。然后B那题String,用stack模拟即可,不用想其他离奇的实现,又是浪费时间。

Problem - F - Codeforces-Photography

题意:在5000个带权点,5000条边的无向图中,找连续,且能无折返遍历的,且最多可以选5个点,找到最大的权重之和。

思路:一个很好的预处理思想:一条路径上共 5 个点,枚举 2 3 4 这三个点,1 和 5 一定取 2 和 4 出边前四大的。

//////网络寻路:https://www.luogu.com.cn/problem/P8605
//////一个很好的预处理思想:一条路径上共 5 个点,枚举 2 3 4 这三个点,1 和 5 一定取 2 和 4 出边前四大的。
typedef struct node{
    int a,b,c;
}node;
int n,m;
int arr[5005];
vector<pair<int,int>> vct[5005];
vector<node> v3;               ////直接用vector存(200+ms),存了重复边也不会MLE,也不会TLE,比用set去重(2000+ms)之后跑到快的多的多的多。。
void dfs(int s,node x){      ////预处理所有三个点
    if(x.c!=-1){
        v3.emplace_back(x);
        return;
    }
    if(x.b==-1){
        for(auto v:vct[s]){
            int to=v.second;
            if(to!=x.a){
                x.b=to;
                dfs(x.b,x);
            }
        }
    }
    else if(x.c==-1){
        for(auto v:vct[s]){
            int to=v.second;
            if(to!=x.a&&to!=x.b){
                x.c=to;
                dfs(x.c,x);
            }
        }
    }
}
void solve(){           ////F Photography     这是第二版代码,加上n=2特判,不开longlong即可完美ac....
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>arr[i];
    int ans=0;
    for(int i=1;i<=m;i++){
        int u,v; cin>>u>>v;
        vct[u].emplace_back(arr[v],v);
        vct[v].emplace_back(arr[u],u);
        ans=max(ans,arr[v]+arr[u]);                 ////n=2的情况!!
    }
    for(int i=1;i<=n;i++) {
        node x; x.a=i,x.b=-1,x.c=-1;
        dfs(i,x);
        sort(vct[i].begin(),vct[i].end(),greater<pair<int,int>>());   ////按照权重,从大到小排序。
    }
//    for(int i=1;i<=n;i++){          ////代替dfs预处理三个点
//        sort(vct[i].begin(),vct[i].end(),greater<pair<int,int>>());
//        node x; x.a=i;
//        for(auto v1:vct[i]){
//            x.b=v1.second;
//            for(auto v2:vct[v1.second]){
//                if(v2.second!=i){
//                    x.c=v2.second;
//                    v3.emplace_back(x);
//                }
//            }
//        }
//    }
    for(auto s:v3){
        int l=s.a,m=s.b,r=s.c,nex1=-1,nex11=-1,nex2=-1,nex22=-1,res=arr[l]+arr[m]+arr[r];
        for(auto v:vct[l]){
            int to=v.second;
            if(to==l) continue;
            if(nex1==-1&&to!=m&&to!=r) nex1=to;
            else if(to!=m&&to!=r&&to!=nex1){
                nex11=to;
                break;
            }
        }
        for(auto v:vct[r]){
            int to=v.second;
            if(to==r) continue;
            if(nex2==-1&&to!=l&&to!=m) nex2=to;
            else if(to!=l&&to!=m&&to!=nex1&&to!=nex2){
                nex22=to;
                break;
            }
        }
        if(nex1!=-1&&nex2!=-1){                             ////这是第二版代码  这里的if判断更强。
            if(nex1!=nex2) res+=arr[nex1],res+=arr[nex2];
            else if(nex11!=-1&&nex22!=-1){
                if(arr[nex11]>=arr[nex22]) res+=arr[nex2],res+=arr[nex11];
                else if(arr[nex22]>arr[nex11]) res+=arr[nex1],res+=arr[nex22];
            }
            else if(nex11!=-1) res+=arr[nex2],res+=arr[nex11];
            else if(nex22!=-1) res+=arr[nex1],res+=arr[nex22];
            else res+=arr[nex1];
        }
        else if(nex1!=-1) res+=arr[nex1];
        else if(nex2!=-1) res+=arr[nex2];
        ans=max(ans,res);
    }
    cout<<ans;
}
////这个代码比用set存预处理跑的快的多

要注意的点:注意n=2,的情况,还有千万不能开long long!开long long会导致TLE30 或 MLE30.

posted @ 2024-05-22 16:57  osir  阅读(73)  评论(0编辑  收藏  举报