USACO3.3

26 篇文章 0 订阅

fence

  • 欧拉回路

    主要思路就是一个dfs,一开始写了一个while卡在倒数第二个case..前面坑了一次重边和一个非零起始点.

    下面代码(模板的思路)是随便一个点开始,(因为大小顺序所以优先队列来水…)然后最后记得倒序输出.这样也解释了为什么一路搜下去万一先碰到奇数点的问题,因为倒序的话,奇数点是最先入队的(每次dfs最后一步入队嘛)

void euler(int p){
    while (net[p].size()) {
        int nextV=net[p].top();
        net[p].pop();
        if (road[p][nextV]==0) {
            continue;
        }else{
            road[p][nextV]--;
            road[nextV][p]--;
            deg[p]--;deg[nextV]--;
            euler(nextV);
            if (road[p][nextV]) {
                net[p].push(nextV);
            }
        }
    }
    vis.push_back(p);
}
  • 这道题毒性太重,第一次有想贴完整代码冲动

    /*
    ID: leidar11
    PROG: shopping
    LANG: C++11
    */
    
    #include <iostream>
    
    
    #include <fstream>
    
    using namespace std;
    const int maxn=1001;
    struct offer{
      int num[maxn];
      int price;
    }special[100];
    int id[6],oriprice[maxn],need[maxn];
    int k[6],dp[6][6][6][6][6];//dp&loop
    ifstream fin("shopping.in");
    ofstream fout("shopping.out");
    
    #define res0(i,n) for(i=0;i<=n;i++)
    
    
    #define res(i,n) for(i=1;i<=n;i++)
    
    
    #define CUR dp[k[1]][k[2]][k[3]][k[4]][k[5]]
    
    
    #define min(a,b) ((a<b)?a:b)
    
    int main(){
      int totoffer,totneed,temp,tempnum,ord,code;
      fin>>totoffer;
      res(temp, totoffer)
      {
          fin>>tempnum;
          res(ord, tempnum)
          {
              fin>>code;
              fin>>special[temp].num[code];
          }
          fin>>special[temp].price;
      }
      fin>>totneed;
      res(temp, totneed)
      {
          fin>>id[temp];
          fin>>need[id[temp]]>>oriprice[id[temp]];
      }
      res0(k[1], need[id[1]])res0(k[2], need[id[2]])res0(k[3], need[id[3]])
      res0(k[4], need[id[4]])res0(k[5], need[id[5]])res(temp, totneed)
      CUR+=k[temp]*oriprice[id[temp]];
    
      res(temp, totoffer)
      for (k[1]=special[temp].num[id[1]]; k[1]<=need[id[1]]; k[1]++) {
          for (k[2]=special[temp].num[id[2]]; k[2]<=need[id[2]]; k[2]++) {
              for (k[3]=special[temp].num[id[3]]; k[3]<=need[id[3]];k[3]++ ) {
                  for (k[4]=special[temp].num[id[4]]; k[4]<=need[id[4]]; k[4]++) {
                      for (k[5]=special[temp].num[id[5]]; k[5]<=need[id[5]]; k[5]++) {
                          CUR=min(CUR,dp[k[1]-special[temp].num[id[1]]][k[2]-special[temp].num[id[2]]][k[3]-special[temp].num[id[3]]][k[4]-special[temp].num[id[4]]][k[5]-special[temp].num[id[5]]]+special[temp].price);
                      }
                  }
              }
          }
      }
      fout<<dp[need[id[1]]][need[id[2]]][need[id[3]]][need[id[4]]][need[id[5]]]<<endl;
      return 0;
    }

range

​ 递推

if (len[row] == '1')
{
  dia[line][row] = dia[line-1][row-1]+1;
  lef[line][row] = lef[line][row-1]+1;
  up[line][row]  = up[line-1][row]+1;
  dia[line][row] = min(dia[line][row], lef[line][row]);
  dia[line][row] = min(dia[line][row], up[line][row]);
  for (int add = 2; add <= dia[line][row]; ++add)
  {
    cnt[add]++;
  }//这里的叠加可以放到输出时候再来一个递推的...
}
else
{
  dia[line][row] = lef[line][row] = up[line][row] = 0;
}

game1

左右取数,博弈DP…

if ( (len & 1) != (Num & 1))//player1 makes dp max
{
  dp[begPos][endPos] = max(number[begPos] + dp[begPos+1][endPos],
                           number[endPos] + dp[begPos][endPos-1]);
}
else//player2 makes dp min
{
  dp[begPos][endPos] = min(dp[begPos+1][endPos] , dp[begPos][endPos-1]);
}

*camlot

SPFA(Shortest Path Faster Algorithm)

算法大致流程是用一个队列来进行维护。 初始时将源加入队列。 每次从队列中取出一个元素,并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队。 直到队列为空时算法结束。

设Dist代表S到I点的当前最短距离,Fa代表S到I的当前最短路径中I点之前的一个点的编号。开始时Dist全部为+∞,只有Dist[S]=0,Fa全部为0。

维护一个队列,里面存放所有需要进行迭代的点。初始时队列中只有一个点S。用一个布尔数组记录每个点是否处在队列中。

每次迭代,取出队头的点v,依次枚举从v出发的边v->u,设边的长度为len,判断Dist[v]+len是否小于Dist[u],若小于则改进Dist[u],将Fa[u]记为v,并且由于S到u的最短距离变小了,有可能u可以改进其它的点,所以若u不在队列中,就将它放入队尾。这样一直迭代下去直到队列变空,也就是S到所有的最短距离都确定下来,结束算法。若一个点入队次数超过n,则有负权环。

优化算法 SLF 和 LLL:

SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)

fin >> maxC >> maxR;//注意顺序

    for (r = 0; r < maxR; ++r)
    {
        for (c = 0; c < maxC; ++c)
        {
            cost[r][c][1] = kdis[r][c] = max(abs(r - x), abs(c - y));
        }
    }//king

    while (fin >> temp >> y)
    {
        x = temp - 'A' , y--;
        bfs(x, y);
        for (r = 0; r < maxR; ++r)
        {
            for (c = 0; c < maxC; ++c)
            {
                cost[r][c][0]+= dis[r][c][0];
                cost[r][c][1] = min(cost[r][c][1],dis[r][c][1] - dis[r][c][0]);
            }
        }
    }//knight

void bfs(int px, int py)
{
    memset(inq, 0, sizeof(inq));
    for (r = 0; r < maxR; ++r)
    {
        for (c = 0; c < maxC; ++c)
        {
            dis[r][c][0] = dis[r][c][1] = inf;
        }
    }//iniliatiaze

    dis[px][py][0] = 0;
    while (que.size())
    {
        que.pop();
    }

    que.push(Node(px,py,0));
    //用spfa优化
    /*
     对于每个骑士都需要初始化,不然会爆空间(存所有骑士)
     */
    while (que.size())
    {
        Node Now = que.front();
        que.pop();
        inq[Now.x][Now.y][Now.k] = false;
        int d = dis[Now.x][Now.y][Now.k];
        int k = Now.k;

        for (int dre = 0; dre < 8; ++dre)
        {
            int x = Now.x + kx[dre],y = Now.y + ky[dre];
            if (x < 0 || x >= maxR || y < 0 || y >= maxC) {
                continue;
            }
            if (dis[x][y][k] > d+1)
            {
                dis[x][y][k] = d+1;
                if (!inq[x][y][k])
                {
                    inq[x][y][k] = true;
                    que.push(Node(x,y,k));
                }
            }
        }

        if( !k && dis[Now.x][Now.y][1] > d + kdis[Now.x][Now.y])
        {
            dis[Now.x][Now.y][1] = d + kdis[Now.x][Now.y];
            if (!inq[Now.x][Now.y][1])
            {
                inq[Now.x][Now.y][1] = true;
                que.push(Node(Now.x,Now.y,1));
            }
        }//important:
        /*
         判断带上王的距离,也就是王走到那里的距离+d
         */
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值