[POI2005]DWU-Double-row

有2n个士兵站成两排,他们需要被重新排列,以保证每一排里没有同样高的士兵——这样我们就说,士兵们被合理地安排了位置。 每次操作可以交换两个在同一位置(但不在同一排)的士兵。你的任务是用最少的操作来确保士兵们被合理地安排了位置。 例如: 有18个士兵站成两排,箭头标明了重新安排士兵位置的正确方式(图飞了?)。 写一个这样的程序: 读入n与士兵的身高,以及他们最初所站的位置,确保以最小的交换(站在同一位置的不同排的士兵)的次数来合理地安排士兵的位置,输出操作数。

Solution

我最菜了。

听一些dalao说要染色,于是我就有了一些NAIVE的想法,把每一列的两个点之间连一条边,既然每个点的度数最多为2,那么它最后一定是一堆环,我们要么全部正着走,要么都反着走,所以我们对每个联通块都做一遍就可以了。

Code

#include<iostream> 
#include<cstdio>
#define N 100002
using namespace std;
int head[N],tot,a[N],b[N],ans,pos[2],n,ma; 
bool vis[N];
struct edge{
    int n,to,tag;
}e[N<<2];
inline void add(int u,int v,int tag){
    e[++tot].n=head[u];
    e[tot].to=v;
    e[tot].tag=tag;
    head[u]=tot;
}
void dfs(int u,int fa){
    vis[u]=1;
    for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
        int v=e[i].to;
        pos[e[i].tag]++;
        if(!vis[v])dfs(v,u);
        break;
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d",&a[i]),ma=max(ma,a[i]);
    for(int i=1;i<=n;++i)scanf("%d",&b[i]),add(a[i],b[i],1),add(b[i],a[i],0),ma=max(ma,b[i]);
    for(int i=1;i<=ma;++i)if(!vis[i]){
        pos[0]=pos[1]=0;
        dfs(i,0);
        ans+=min(pos[0],pos[1]); ;
    }
    cout<<ans;
    return 0;
}

获得了40pts

emmm

有一个问题就是说有些数会出现一次,因为每个点度数最多为2,不可能是基环树,只能是一条链,那么GG了。

我们把每列看成一个点,如果两列必须一样连0边,否则连1边,染色即可。

真·Code

#include<iostream> 
#include<cstdio>
#define N 100002
using namespace std;
int head[N],tot,x,ans,pos[2],n,pre[N],co[N]; 
bool vis[N];
struct edge{
    int n,to,tag;
}e[N<<2];
inline void add(int u,int v,int tag){
    e[++tot].n=head[u];
    e[tot].to=v;
    e[tot].tag=tag;
    head[u]=tot;
}
void dfs(int u,int c){
    vis[u]=1;pos[c]++;
    for(int i=head[u];i;i=e[i].n)if(!vis[e[i].to]){
        int v=e[i].to;
        dfs(v,c^e[i].tag);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
      scanf("%d",&x);
      if(pre[x]){
          add(i,pre[x],1);
          add(pre[x],i,1);
      }
      else pre[x]=i;
    }  
    for(int i=1;i<=n;++i){
      scanf("%d",&x);
      if(pre[x]){
      add(i,pre[x],co[x]);
      add(pre[x],i,co[x]);
      }
      else pre[x]=i,co[x]=1;
    } 
    for(int i=1;i<=n;++i)if(!vis[i]){
        pos[0]=pos[1]=0;
        dfs(i,0);
        ans+=min(pos[0],pos[1]); 
    }
    cout<<ans;
    return 0;
}

 

转载于:https://www.cnblogs.com/ZH-comld/p/9872971.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值