USACO4.1 两道算法题

更棒的算法

nuggets

//这居然过了......
sort(arr, arr+n);
if (n == 1 || arr[0] == 1 || alleven)
{
    fout << "0" << endl;
}//枚举了这三种情况后生成(背包)200000以前的所有,如果mp = 200000-1那么输出0,否则mp...
  • 结论(之前数论白学了系列QAQ)

    • 有两个数p,q,且gcd(q,p)=1,则最大无法表示成px+qy(x>=0,y>=0)的数是pq-q-p
    • 而且数越多,这个值只会越小。
    • 取上界为256*256-256*2 = 65024//这也就证明了..上面的ac
    • 判断无限解可以按上面的方法,另外也可以算所有的数的最大公约数。如果不是1,也就是说这些数不互质,那么不被这个最大公约数整除的数一定构造不出来。当且仅当这种情况会有无限解。
    • 优化算法 这道题其实是可以做到O(N^2)。 令A1表示所有鸡块中最小的那种, 如果有连续A1个数都可以打到,那么之后所有的数都是可以达到的(每次加上A1就行了)。
  • 标准解法用了尝试过的循环数组

    while (pos < 2000000000)
     { /* bound as stated */
    
      /* if last 256 were all possible, we are done */
      if (pos - last > 256) break; 
    
      if (!cando[lv]) 
        last = pos; /* this isn't possible, update last impossible */
      else 
       { /* this is possible */
        cando[lv] = 0; /* mark pos+256 as impossible */
    
        /* mark pos + size as possible for each package size */
        for (lv2 = 0; lv2 < nsize; lv2++)
          cando[(lv+sizes[lv2])%256] = 1;
       }
    
      /* update lv & pos */
      lv = (++pos) % 256; 
     }

另外感觉USACO的机器升级了XD

fence6

给出n条边长度,每条边两个端点相交边的序号,求最小环

这道题难点有二:

  • 序号很麻烦..坑了一晚上

    主要是不是逆时针或者顺时针给的,需要判断交点

    O(n2)扫两遍,用一个变量标志id

    //扫一个数组,
    for (int i = 1; i <= totF; ++i)
    {
          if (F[i].rr == 0)//这样id一定最小
          {
              F[i].rr = ++d;//新的id
    
              for (int p = 1; p <= F[i].r[0]; p++) {
                  int k = F[i].r[p];//更新rr位置
                //确认对应位置,给id
                  int inRR = false;
                  for (int s = 1; s <= F[k].r[0]; s++) {
                      if (F[k].r[s] == i) {
                          inRR = true;
                          break;
                      }
                  }
                  if (inRR) {
                      F[k].rr = d;
                      continue;
                  }
                  F[k].ll = d;
              }
          }
    
          if (F[i].ll == 0)
          {
              //和上面相同
          }
    }
  • 最小环

    有了id之后就可以最小环了

    思路是枚举每一条边oo最短路

    FLOYD改进版本可以过

    for (int eg = 1; eg <= totF; eg++) //枚举边
    {
          int fr = F[eg].ll,to = F[eg].rr;
          //初始化距离矩阵,该边为oo
          for (int i = 1; i <= d; i++) {
              for (int j = 1; j <= d; j++) {
                  dis[i][j] = inf;
              }
              //dis[i][i] = 0;
          }
          for (int i = 1; i <= totF; i++) {
              if (i != eg) {
                  int fr = F[i].ll,to = F[i].rr;
                  dis[fr][to] =dis[to][fr] = F[i].len;
              }
          }
            //floyd
          for (int by = 1;  by <= d; by ++) {
              for (int fr = 1; fr <= d; fr ++) {
                  for (int to = 1; to <= d; to ++) {
                      dis[fr][to] = min(dis[fr][to],dis[fr][by]+dis[by][to]);
                  }
              }
          }
            //当有另一条路过去的时候,那么就是最小环的一半
          for (int by = 1; by <= d; by++) {
              if(by != fr && by != to){
                  ans = min(ans, F[eg].len+ dis[fr][by] + dis[by][to]);          
              }
          }
      }
    • 当然,这是单源最短路径,所以可以用SPFA,dijkstra来优化速度
    • 据说搜索+剪枝也能过
    //nocow上没有id化的代码
    int dijkstra(int z){
    int i,j,k;
    for(i=1;i<=n;i++){dis[i]=MAX;isi[i]=0;}//初始化
    for(i=1;i<=map[0][z][0];i++)
      {
        bef[map[0][z][i]]=z;
        dis[map[0][z][i]]=len[z];
      }
    while(1){
        j=0;
            k=MAX;
        for(i=1;i<=n;i++)
            if(dis[i]<k && isi[i]==0){
                j=i;
                k=dis[i];
            }//最近d
        if(j==0)break;//找不到
        if(j==z)return dis[z];//当前
        isi[j]=1;//最优标记
        for(i=1;i<=map[0][j][0];i++)
            if(map[0][j][i]==bef[j])break;
        if(i==map[0][j][0]+1)
            k=0;//0方向
        else 
            k=1;//1方向
        for(i=1;i<=map[k][j][0];i++){
            if(dis[map[k][j][i]]>dis[j]+len[j]){
                dis[map[k][j][i]]=dis[j]+len[j];
                bef[map[k][j][i]]=j;
            }
        }
    }
    return MAX;
    }
    • 其实这道题时间大多数花在纠结是用vector还是set
    • 搜索也写烂了几次,所以其实很多看起来很炫酷的东西其实并不重要,重要的是即使是枚举也先要实现代码.
  • 今(昨)天有一个很开心的事是发现xcode怎么输入输出不是绝对路径的文件了23333

你可能感兴趣的:(算法,gcd)