zoukankan      html  css  js  c++  java
  • UVa 10735

    链接:

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1676

    题意:

    给出一个V个点和E条边(1≤V≤100,1≤E≤500)的混合图(即有的边是无向边,有的边是有向边),
    试求出它的一条欧拉回路,如果没有,输出无解信息。输入保证在忽略边的方向之后图是连通的。

    分析:

    很多混合图问题(例如,混合图的最短路)都可以转化为有向图问题,方法是把无向边拆成两条方向相反的有向边。
    可惜本题不能使用这种方法,因为本题中的无向边只能经过一次,
    而拆成两条有向边之后变成了“沿着两个相反方向各经过一次”。所以本题不能拆边,而只能给边定向。
    假设输入的原图为G。首先把它的无向边任意定向,然后把定向后的有向边单独组成另外一个图G'。
    具体来说,初始时G'为空,对于G中的每条无向边u-v,把它改成有向边u->v,然后在G'中连一条边u->v
    (注意这个定向是任意的。如果定向为v->u,则在G'中连一条边v->u)。
    接下来检查每个点i在G中的入度和出度。如果所有点的入度和出度相等,则现在的G已经存在欧拉回路。
    假设一个点的入度为2,出度为4,则可以想办法把一条出边变成入边(前提是那条出边原来是无向边),
    这样入度和出度就都等于3了;一般地,如果一个点的入度为in(i),出度为out(i),
    则只需把出度增加(in(i)-out(i))/2即可(因为总度数不变,此时入度一定会和出度相等)。
    如果in(i)和out(i)的奇偶性不同,则问题无解。
    如果把G'中的一条边u->v反向成v->u,则u的出度减1,v的出度加1,
    就像是把一个叫“出度”的物品从结点u“运输”到了结点v。是不是很像网络流?
    也就是说,满足out(i)>in(i)的每个点能“提供”一些“出度”,而out(i)<in(i)的点则“需要”一些“出度”。
    如果能算出一个网络流,把这些“出度”运输到需要它们的地方,问题就得到了解决(有流量的边对应"把边反向"操作)。
    具体实现见代码。

    代码:

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <queue>
      4 #include <vector>
      5 using namespace std;
      6 
      7 /// 结点下标从0开始,注意maxn
      8 struct Dinic {
      9     static const int maxn = 1e3 + 5;
     10     static const int INF = 0x3f3f3f3f;
     11     struct Edge {
     12         int from, to, cap, flow;
     13     };
     14 
     15     int n, m, s, t; // 结点数,边数(包括反向弧),源点编号和汇点编号
     16     vector<Edge> edges; // 边表。edges[e]和edges[e^1]互为反向弧
     17     vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
     18     bool vis[maxn]; // BFS使用
     19     int d[maxn]; // 从起点到i的距离
     20     int cur[maxn]; // 当前弧下标
     21 
     22     void init(int n) {
     23         this->n = n;
     24         edges.clear();
     25         for(int i = 0; i < n; i++) G[i].clear();
     26     }
     27     void AddEdge(int from, int to, int cap) {
     28         edges.push_back((Edge){from, to, cap, 0});
     29         edges.push_back((Edge){to, from, 0, 0});
     30         m = edges.size();
     31         G[from].push_back(m-2);
     32         G[to].push_back(m-1);
     33     }
     34     bool BFS() {
     35         memset(vis, 0, sizeof(vis));
     36         queue<int> Q;
     37         Q.push(s);
     38         vis[s] = 1;
     39         d[s] = 0;
     40         while(!Q.empty()) {
     41             int x = Q.front();  Q.pop();
     42             for(int i = 0; i < G[x].size(); i++) {
     43                 Edge& e = edges[G[x][i]];
     44                 if(!vis[e.to] && e.cap > e.flow) { // 只考虑残量网络中的弧
     45                     vis[e.to] = 1;
     46                     d[e.to] = d[x] + 1;
     47                     Q.push(e.to);
     48                 }
     49             }
     50         }
     51         return vis[t];
     52     }
     53     int DFS(int x, int a) {
     54         if(x == t || a == 0) return a;
     55         int flow = 0, f;
     56         for(int& i = cur[x]; i < G[x].size(); i++) { // 从上次考虑的弧
     57             Edge& e = edges[G[x][i]];
     58             if(d[x]+1 == d[e.to] && (f=DFS(e.to, min(a, e.cap-e.flow))) > 0) {
     59                 e.flow += f;
     60                 edges[G[x][i]^1].flow -= f;
     61                 flow += f;
     62                 a -= f;
     63                 if(a == 0) break;
     64             }
     65         }
     66         return flow;
     67     }
     68     int Maxflow(int s, int t) {
     69         this->s = s;  this->t = t;
     70         int flow = 0;
     71         while(BFS()) {
     72             memset(cur, 0, sizeof(cur));
     73             flow += DFS(s, INF);
     74         }
     75         return flow;
     76     }
     77     vector<int> Mincut() { // 在Maxflow之后调用
     78         vector<int> ans;
     79         for(int i = 0; i < edges.size(); i++) {
     80             Edge& e = edges[i];
     81             if(vis[e.from] && !vis[e.to] && e.cap > 0) ans.push_back(i);
     82         }
     83         return ans;
     84     }
     85 } dc;
     86 
     87 const int UP = 500 + 5;
     88 int n, m, f[UP], b[UP], directed[UP], out[UP], id[UP];
     89 vector<int> ans, edge[UP], vis[UP];
     90 
     91 void euler(int v) {
     92     for(int i = 0; i < edge[v].size(); i++) {
     93         if(vis[v][i]) continue;
     94         vis[v][i] = true;
     95         euler(edge[v][i]);
     96         ans.push_back(edge[v][i]+1);
     97     }
     98 }
     99 
    100 void output_ans() {
    101     for(int i = 0; i < n; i++) { edge[i].clear();  vis[i].clear(); }
    102     for(int i = 0; i < m; i++) {
    103         bool rev = false;
    104         if(!directed[i] && dc.edges[id[i]].flow > 0) rev = true;
    105         if(rev) { edge[b[i]].push_back(f[i]);  vis[b[i]].push_back(false); }
    106         else { edge[f[i]].push_back(b[i]);  vis[f[i]].push_back(false); }
    107     }
    108     ans.clear();
    109     euler(0);
    110     printf("1");
    111     for(int i = ans.size() - 1; i >= 0; i--) printf(" %d", ans[i]);
    112     printf("
    ");
    113 }
    114 
    115 int main() {
    116     int T;
    117     char s[9];
    118     scanf("%d", &T);
    119     while(T--) {
    120         scanf("%d%d", &n, &m);
    121         dc.init(n+2);
    122         memset(out, 0, sizeof(out));
    123         for(int i = 0; i < m; i++) {
    124             scanf("%d%d%s", &f[i], &b[i], s);
    125             directed[i] = (s[0] == 'D');
    126             f[i]--;  b[i]--;
    127             out[f[i]]++;  out[b[i]]--;
    128             if(!directed[i]) {
    129                 id[i] = dc.edges.size();
    130                 dc.AddEdge(f[i], b[i], 1);
    131             }
    132         }
    133 
    134         bool ok = true;
    135         for(int i = 0; i < n; i++) if(out[i] % 2 != 0) { ok = false;  break; }
    136         if(ok) {
    137             int start = n, finish = n+1, sum = 0;
    138             for(int i = 0; i < n; i++) {
    139                 if(out[i] > 0) { dc.AddEdge(start, i, out[i]/2);  sum += out[i]/2; }
    140                 else if(out[i] < 0) dc.AddEdge(i, finish, -out[i]/2);
    141             }
    142             if(sum != dc.Maxflow(start, finish)) ok = false;
    143         }
    144         if(ok) output_ans();
    145         else printf("No euler circuit exist
    ");
    146         if(T) printf("
    ");
    147     }
    148     return 0;
    149 }
  • 相关阅读:
    oracle中Blob和Clob类型的区别
    为什么要分库分表
    Enable file editing in Visual Studio's debug mode
    SQL Server Dead Lock Log
    Debug .NET Framework Source
    SQL Server text field里面有换行符的时候copy到excel数据会散乱
    诊断和修复Web测试记录器(Web Test Recorder)问题
    Can't load Microsoft.ReportViewer.ProcessingObjectModel.dll
    'telnet' is not recognized as an internal or external command
    Linq to XML
  • 原文地址:https://www.cnblogs.com/hkxy125/p/9551700.html
Copyright © 2011-2022 走看看