返回顶部
大江东去,浪淘尽,千古风流人物。故垒西边,人道是,三国周郎赤壁。乱石穿空,惊涛拍岸,卷起千堆雪。江山如画,一时多少豪杰。遥想公瑾当年,小乔初嫁了,雄姿英发。羽扇纶巾,谈笑间,樯橹灰飞烟灭。故国神游,多情应笑我,早生华发。人生如梦,一尊还酹江月。

noip2017day2总结

3个题都有或大或小的失误

第一题,奶酪,bjj的位置写错了,wa了3个点

#include<bits/stdc++.h>
#define ll long long
#define maxn 1100
using namespace std;
 
inline ll read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
 
ll n,h,r,x[maxn],y[maxn],z[maxn],ok,bjj;
 
bool bj[maxn];
 
ll dis(int a,int b){
    return (x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b])+(z[a]-z[b])*(z[a]-z[b]);
}
 
void dfs(int bh){
    if(z[bh]+r>=h)ok=1;
    if(ok) return ;
    for(int i=1;i<=n;i++){
        if(bj[i]) continue;
        if(dis(bh,i)<=4*r*r) {bj[i]=1;dfs(i);}
    }
}
 
int main(){
    ll t=read();
    while(t--){
        n=read();h=read();r=read();bjj=0;
        for(int i=1;i<=n;i++) x[i]=read(),y[i]=read(),z[i]=read();
        for(int i=1;i<=n;i++){
            if(z[i]-r<=0) {
                memset(bj,0,sizeof(bj));
                bj[i]=1;
                ok=0;//bjj=0;(就因为放这里错了)虽然到现在还不知为什么啊啊啊
                dfs(i);
                if(ok) {
                    bjj=1;
                    break;
                }
            }
        }
        if(!bjj) printf("No\n");
          else printf("Yes\n");
    }
    return 0;
}

 

第二题宝藏写的暴力搜索,想状压想好久都没想出来就放弃了。。不过剪枝时少了一个,只有60分,先发个70分的把

 

#include<bits/stdc++.h>
#define maxn 15
using namespace std;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,mp[maxn][maxn],tmp,ans=0x3f3f3f3f,bj[maxn];

void dfs(int bh,int dep){
    if(dep==n){
        ans=min(ans,tmp);return;
    }
    if(tmp>ans) return;//这个剪枝没考虑到
    for(int i=1;i<=n;i++){
        if(bj[i]) continue;
        for(int j=1;j<=n;j++){
            if(mp[j][i]==0x3f3f3f3f||(!bj[j])||(i==j)) continue;
            bj[i]=bj[j]+1;tmp+=bj[j]*mp[j][i];
            dfs(i,dep+1);
            tmp-=bj[j]*mp[j][i];bj[i]=0;
        }
    }
}

int main(){
    n=read();m=read();
    memset(mp,0x3f3f3f3f,sizeof(mp));
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        mp[u][v]=mp[v][u]=min(mp[u][v],read());
    }
    for(int i=1;i<=n;i++){
        memset(bj,0,sizeof(bj));
        tmp=0;
        bj[i]=1;
        dfs(i,1);
    }
    printf("%d",ans);
    return 0;
}

正解还在思考,想出来了再补充。。。。。

补充正解

正解思路可以是状压加dfs,考场上敲了一个,不过总感觉可能要炸就直接改成了暴力。。。。。考场上是敲的状压加dfs好像没回溯,还好没交不然分更低

直接用f【i】表示i状态时的最优解,因为起点位置的不确定就直接枚举每一个点当起点,其他的就是基本操作了。

 

上代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define maxn 13
using namespace std;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,f[1<<12],l[maxn],ans,mp[maxn][maxn];//l[i]指i号节点到起点的距离

void dfs(int s){
    if(s==(1<<n)-1) return;
    for(int i=1;i<=n;i++){
        if(!((1<<(i-1))&s)) continue;//i没选过就卡掉,转移方程是从i到j
        for(int j=1;j<=n;j++){
            if((mp[i][j]==inf)||((1<<(j-1))&s)) continue;//同理,j选过就卡掉,ij间无边也卡掉
            if(f[s|(1<<(j-1))]>f[s]+mp[i][j]*l[i]){
                int k=l[j];l[j]=l[i]+1;//用k存原来的l[j]中的值,用于回溯
                f[s|(1<<(j-1))]=f[s]+mp[i][j]*l[i];//标准转移方程
                dfs(s|(1<<(j-1)));
                l[j]=k;//回溯,考场上没想到的东西,但也不知去掉会不会错,还没试过
            } 
        }
    }
}
int main(){
    n=read();m=read();
    memset(mp,inf,sizeof(mp));
    ans=inf;
    for(int i=1;i<=m;i++){
        int a=read(),b=read();
        mp[a][b]=mp[b][a]=min(mp[a][b],read());
    }
    for(int i=1;i<=n;i++){//依次枚举
        memset(l,0,sizeof(l));
        memset(f,inf,sizeof(f));//初始化
        l[i]=1;f[1<<(i-1)]=0;
        dfs(1<<(i-1));
        ans=min(ans,f[(1<<n)-1]);
    }
    printf("%d",ans);//大功告成
    return 0;
}

 

 闲来无事又翻了下题解,发现这个方法有bug,中间"存在更优解"的那一行的优化是不正确的,忽略了不同的disdisdis取值对后续搜索的影响。”所以单独记录一个点集而不记录每个点在该点集中的深度状态是不完整的,所以我们要改进状态,消除后效性————摘抄自原句

 所以我们要用三维f[i][j][k]其中i用于当前节点,j表示状态,k指节点深度

 

直接上代码了

#include<bits/stdc++.h>
#define maxn 14
#define inf 0x3f3f3f3f
using namespace std;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return f*x;
}

int n,m,mp[maxn][maxn],f[maxn][1<<13][maxn],ans=inf,l[maxn];

void dfs(int cost,int zt,int dep){
    if(cost>ans) return;
    if(zt==(1<<n)-1) {ans=cost;return;}
    for(int i=1;i<=n;i++){
        if(!((1<<(i-1))&zt)) continue;
        for(int j=1;j<=n;j++){
            if((mp[i][j]==inf)||((1<<(j-1))&zt)) continue;
            if(f[j][zt|(1<<(j-1))][dep+1]>cost+l[i]*mp[i][j]){
                l[j]=l[i]+1;
                f[j][zt|(1<<(j-1))][dep+1]=cost+l[i]*mp[i][j];
                dfs(cost+l[i]*mp[i][j],zt|(1<<(j-1)),dep+1);
            }
        }
    }
}

int main(){
    n=read();m=read();
    memset(mp,inf,sizeof(mp));
    for(int i=1;i<=m;i++){
        int a=read(),b=read();
        mp[a][b]=mp[b][a]=min(mp[b][a],read());
    }
    for(int i=1;i<=n;i++){
        memset(l,0,sizeof(l));
        memset(f,inf,sizeof(f));
        l[i]=1;f[i][1<<(i-1)][1]=0;
        dfs(0,1<<(i-1),1);
    }
    printf("%d",ans);
    return 0;
}

这题做的真艰难

 

最后一题正解不会,打了个暴力准备骗个30分忘关文件了。。。直接爆零

 

暴力程序就不给了

 

未完待续

 

posted @ 2019-01-22 14:50  plysc  阅读(219)  评论(0编辑  收藏  举报