zoukankan      html  css  js  c++  java
  • 【A* 网络流】codechef Chef and Cut

    高嘉煊讲的杂题;A*和网络流的练手题

    题目大意

    https://s3.amazonaws.com/codechef_shared/download/translated/SEPT16/mandarin/CHEFKC.pdf

    一张有向带权图,固定$S$和$T$,求权值第$k$小的割。

    $n le 77,mle 777,k le 777$


    题目分析

    考虑如何描述每一种割:$p_i=1$表示$S$与$i$连通;$p_i=0$表示$i$与$T$连通。注意到这里的${p_i}$与每种割是一一对应的,那么就可以以$p_i$为状态进行A*扩展求第$k$大状态。

    接下去的问题就是如何计算${p_i}$的权值。那么对于$p_i=1$,连边$(S,i,INF)$表示$(S,i)$无法割去;$p_i=0$同理。对于这张图做最小流即可。

    最后可能是一个A*不同写法上的技巧。讲课时候讲的是一个状态$(len,{p_i},val)$表示只确认前$len$位的状态$p_i$的权值$val$。这种扩展是每次一步步确认元素,时空效率都不高。另一种写法直接$(len,{p_i},val)$表示$n$个点的状态为${p_i}$,确定不改变 前$len$个元素,这个情况下的权值$val$。每次转移的时候,枚举新状态确认的长度$len'=len+1cdots n$,保留前$len'-1$个状态并将$len'$位取反(这个处理是为了保证不重不漏遍历所有状态),然后以此状态处理出的最小割作为新的状态,这样就能保证省略很多中途步骤的无用状态而直接取当前状态的最优方案(因为既然要按顺序,那么必定从每个子状态的最优状态再进一步考虑)。

    反正效率还不错,cc榜rk4.

    1A还行

      1 #include<bits/stdc++.h>
      2 typedef long long ll;
      3 const int maxn = 103;
      4 const int maxm = 5035;
      5 const int INF = 1e9;
      6 
      7 struct Edge
      8 {
      9     int u,v,f,c;
     10     Edge(int a=0, int b=0, int c=0, int d=0):u(a),v(b),f(c),c(d) {}
     11 }edges[maxm],sv[maxm];
     12 struct node
     13 {
     14     int len,val;
     15     bool a[maxn];
     16     bool operator < (node a) const
     17     {
     18         return val > a.val;
     19     }
     20     void init(){memset(a, 0, sizeof a);}
     21 }tmp,trans;
     22 bool vis[maxn];
     23 int n,m,k,S,T,sta,end;
     24 int edgeTot,head[maxn],nxt[maxm],lv[maxn];
     25 std::priority_queue<node> q;
     26 
     27 void addedge(int u, int v, int c)
     28 {
     29     edges[edgeTot] = Edge(u, v, 0, c), nxt[edgeTot] = head[u], head[u] = edgeTot, ++edgeTot;
     30     edges[edgeTot] = Edge(v, u, 0, 0), nxt[edgeTot] = head[v], head[v] = edgeTot, ++edgeTot;
     31 }
     32 bool buildLevel()
     33 {
     34     std::queue<int> q;
     35     memset(lv, 0, sizeof lv);
     36     q.push(S), lv[S] = 1;
     37     for (int tmp; q.size(); )
     38     {
     39         tmp = q.front(), q.pop();
     40         for (int i=head[tmp]; i!=-1; i=nxt[i])
     41         {
     42             int v = edges[i].v;
     43             if (edges[i].f < edges[i].c&&!lv[v]){
     44                 lv[v] = lv[tmp]+1, q.push(v);
     45                 if (v==T) return true;
     46             }
     47         }
     48     }
     49     return false;
     50 }
     51 int fndPath(int x, int lim)
     52 {
     53     if (!lim||x==T) return lim;
     54     int sum = 0;
     55     for (int i=head[x]; i!=-1&&sum < lim; i=nxt[i])
     56     {
     57         int v = edges[i].v, val = 0;
     58         if (lv[v]==lv[x]+1&&edges[i].f < edges[i].c){
     59             if ((val = fndPath(v, std::min(edges[i].c-edges[i].f, lim-sum)))){
     60                 sum += val, edges[i].f += val, edges[i^1].f -= val;
     61             }else lv[v] = -1;
     62         }
     63     }
     64     return sum;
     65 }
     66 int dinic()
     67 {
     68     int ret = 0, val = 0;
     69     while (buildLevel())
     70         while ((val = fndPath(S, INF))) ret += val;
     71     return ret;
     72 }
     73 void calc(node &x)
     74 {
     75     memset(head, -1, sizeof head), edgeTot = 0;
     76     for (int i=1; i<=m; i++) addedge(sv[i].u, sv[i].v, sv[i].c);
     77     addedge(S, sta, INF), addedge(end, T, INF);
     78     for (int i=1; i<=x.len; i++)
     79         if (x.a[i]) addedge(S, i, INF);
     80         else addedge(i, T, INF);
     81     std::queue<int> q;
     82     x.val = dinic(), q.push(S);
     83     memset(vis, 0, sizeof vis);
     84     for (int i=1; i<=n; i++) x.a[i] = 0;
     85     for (int tmp; q.size(); )
     86     {
     87         tmp = q.front(), q.pop();
     88         for (int i=head[tmp]; i!=-1; i=nxt[i])
     89             if (edges[i].f < edges[i].c){
     90             int v = edges[i].v;
     91             if (!vis[v]) vis[v] = true, x.a[v] = 1, q.push(v);
     92         }
     93     }
     94 }
     95 int main()
     96 {
     97     freopen("CHEFKC.in","r",stdin);
     98     freopen("CHEFKC.out","w",stdout);
     99     scanf("%d%d%d%d%d",&n,&m,&k,&sta,&end), S = 0, T = n+1;
    100     for (int i=1; i<=m; i++) scanf("%d%d%d",&sv[i].u,&sv[i].v,&sv[i].c);
    101     tmp.len = 0, tmp.a[sta] = true, calc(tmp), q.push(tmp);
    102     while (--k)
    103     {
    104         tmp = q.top(), q.pop();
    105         for (int i=tmp.len+1; i<=n; i++)
    106         {
    107             trans.init(), trans.len = i, trans.a[i] = !tmp.a[i];
    108             for (int j=1; j<i; j++) trans.a[j] = tmp.a[j];
    109             calc(trans), q.push(trans);
    110         }
    111     }
    112     printf("%d
    ",q.top().val);
    113     return 0;
    114 }

    END

  • 相关阅读:
    Maven学习
    Oracle_SQL函数-单行函数
    Java 8新特性-5 内建函数式接口
    量子优势
    配置Emeditor编译运行JAVA,附私家珍藏版
    配置Emeditor编译运行JAVA,附私家珍藏版
    Notepad2-mod,轻量级文本编辑器、代替记事本的最佳选择
    三星S7短信不能提示的处理方法
    三星S7短信不能提示的处理方法
    说说宾得机身的十大人性化设定和功能[转]
  • 原文地址:https://www.cnblogs.com/antiquality/p/10771361.html
Copyright © 2011-2022 走看看