LOJ2984[WC2019]远古计算机(构造)


神仙造计算机题。。。计算机造计算机

subtask 1:

理解了这个题的应该都能写出来。

node 1
read 0 a
write a 0

subtask 2:

看到只有一个计算机,内存还只有两个数就明显不能真算了,打表出斐波那契数列,注意要求周期尽量少,所以应该用jmp语句来打表。

 1 node 1
 2 read 0 a
 3 add a 4
 4 jmp a
//可以对照行号看一下,a+4行对应的就是相应的第a项
5 write 0 0 6 write 1 0 7 write 1 0 8 write 2 0 9 write 3 0 10 write 5 0 //自己动手丰衣足食 49 write 701408733 0

subtask 3:

在图上bfs,找出1到n的路径,构造即可。

bfs:

#include
#include
using namespace std;
int G[105],to[250],nxt[250],sz=0,pre[105],st[105],sl=-1;
bool vis[205];
queue<int> Q;
inline void add(int u,int v){
    to[++sz]=v;nxt[sz]=G[u];G[u]=sz;
    to[++sz]=u;nxt[sz]=G[v];G[v]=sz;
}
int main(){
    freopen("oldcomputer3.in","r",stdin);
    freopen("bfs_res.out","w",stdout);
    int n,m,i,u,v;
    bool ok=0;
    scanf("%d%d%d",&i,&n,&m);
    while(m--){
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    vis[1]=1;Q.push(1);
    while(!Q.empty()&&!ok){
        u=Q.front();Q.pop();
        for(i=G[u];i;i=nxt[i])if(!vis[v=to[i]]){
            pre[v]=u;
            if(v==n){ok=1;break;}
            vis[v]=1;
            Q.push(v);
        }
    }
    for(;pre[v];v=pre[v])st[++sl]=v;
    puts("1");
    while(sl>=0)printf("%d\n",st[sl--]);
    return 0;
}

构造:(其实两个完全可以写在一起,懒得改了)

#include
int a[105];
int main(){
    freopen("bfs_res.out","r",stdin);
    freopen("oldcomputer3.out","w",stdout);
    int i,x,m=0;
    while(scanf("%d",&x)==1)a[++m]=x;
    for(i=1;i<=m;++i)printf("node %d\nread %d a\nwrite a %d\n",a[i],a[i-1],a[i+1]);
    return 0;
}

subtask 4:

从51~100号点往回跑最短路,可以发现1~50号点的距离都不超过3,这就提示我们可以根据距离递减来构造方案。

然而dfs构造的方案只能拿60%的分,周期太多了,于是我们乱搞一下:对于每个中转,记录下它之前有几个点,每个结点输出的时候贪心地选前面结点最少的中转先输出就AC了。

#include
#include
#include
#include
#include
using namespace std;
int G[1005],to[4000],nxt[4000],sz=0,d[1005],n;
queue<int> Q;
struct opt{
    int r,w,t;
    opt(){}
    opt(int r,int w,int t):r(r),w(w),t(t){}
};
vector V[1005];
inline bool cmp(opt a,opt b){return a.t<b.t;}
inline void add(int u,int v){
    to[++sz]=v;nxt[sz]=G[u];G[u]=sz;
    to[++sz]=u;nxt[sz]=G[v];G[v]=sz;
}
void dfs(int u,int fa,int t){
    if(u>50&&u<=100){
        V[u].push_back(opt(fa,0,t));
        return;
    }
    int i,v;
    for(i=G[u];i;i=nxt[i])if(d[v=to[i]]==d[u]-1&&V[v].size()<3){
        V[u].push_back(opt(fa,v,t));
        dfs(v,u,t+1);
        return;
    }
}
int main(){
    freopen("oldcomputer4.in","r",stdin);
    freopen("oldcomputer4.out","w",stdout);
    int m,i,j,u,v;
    scanf("%d%d%d",&i,&n,&m);
    while(m--){
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    memset(d,0x3f,sizeof(d));
    for(i=51;i<=100;++i){
        d[i]=0;
        Q.push(i);
    }
    while(!Q.empty()){
        u=Q.front();Q.pop();
        for(i=G[u];i;i=nxt[i])if(d[v=to[i]]==0x3f3f3f3f){
            d[v]=d[u]+1;
            Q.push(v);
        }
    }
    for(i=1;i<=50;++i)dfs(i,0,0);
    for(i=1;i<=1000;++i)if(!V[i].empty()){
        printf("node %d\n",i);
        sort(V[i].begin(),V[i].end(),cmp);
        for(j=0;j"read %d a\nwrite a %d\n",V[i][j].r,V[i][j].w);
    }
    return 0;
}

subtask 5:

这回要认真一点乱搞了。。。用$used_{u,t}$记下$u$在$t$时刻是不是有事做,那么$v$开始中转的时间$d_v$定为最小的$t$使得$t>d_u$且$used_{v,t}$,$used_{v,t+1}$均为$false$。跑10次$Dijkstra$即可。

事实证明邻接表存图60%,vector存图100%,实在不放心可以random_shuffle一下。

#include
#include
#include
#include
#include
using namespace std;
int d[105],pre[105];
bool used[105][25];
vector<int> G[105];
struct node{
    int p,d;
    node(){}
    node(int p,int d):p(p),d(d){}
    inline bool operator <(const node &b)const{return d>b.d;}
};
priority_queue Q;
struct opt{
    int r,w,t;
    opt(){}
    opt(int r,int w,int t):r(r),w(w),t(t){}
};
vector V[105];
inline bool cmp(opt a,opt b){return a.t<b.t;}
inline void dijkstra(int s,int t){
    int i,u,v,dis=1,lst=0;
    node h;
    memset(d,0x3f,sizeof(d));
    while(!Q.empty())Q.pop();
    while(used[s][dis]||used[s][dis+1])++dis;
    Q.push(node(s,d[s]=dis));
    while(!Q.empty()){
        h=Q.top();Q.pop();
        if(d[u=h.p]!=h.d)continue;
        if(u==t)break;
        for(i=0;ii){
            v=G[u][i];dis=d[u]+1;
            while(used[v][dis]||used[v][dis+1])++dis;
            if(dis<d[v]){
                pre[v]=u;
                Q.push(node(v,d[v]=dis));
            }
        }
    }
    v=t;
    while(v!=s){
        used[v][d[v]]=used[v][d[v]+1]=1;
        V[v].push_back(opt(pre[v],lst,d[v]));
        v=pre[lst=v];
    }
    used[s][d[s]]=used[s][d[s]]=1;
    V[s].push_back(opt(0,lst,d[s]));
}
int main(){
    freopen("oldcomputer5.in","r",stdin);
    freopen("oldcomputer5.out","w",stdout);
    int n,m,i,j,u,v;
    scanf("%d%d%d",&i,&n,&m);
    while(m--){
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    for(i=1;i<=10;++i)dijkstra(i,101-i);
    for(i=1;i<=100;++i)if(!V[i].empty()){
        printf("node %d\n",i);
        sort(V[i].begin(),V[i].end(),cmp);
        for(j=0;j"read %d a\nwrite a %d\n",V[i][j].r,V[i][j].w);
    }
    return 0;
}