HDU 2828 Lamp

2017寒假集训 2-C

HDU 2828 Lamp

网络流

传送门:HustOJ

传送门:HDU


题意

N个灯,M个开关。每个开关最多控制两盏灯。
输入N个灯,每个灯受k个开关控制,第i( 0<i<=k )个开关为开或关时这个灯可以亮。输出使灯全亮的开关方案,无解-1。

Lamp 1, the list is “1 ON 3 OFF 9 ON”, that means Lamp 1 will be lighted if the Switch 1 is at the “ON” state OR the Switch 3 is “OFF” OR the Switch 9 is “ON”.

注意如果一个灯受多个开关控制,那么其中任意一个开关状态符合时这个灯就能亮。


思路

网上说DLX搜索可以做,但我不会DLX。所以网络流做的。

如果一个开关控制两个灯,且两个灯状态要求相同,那么添加边:源点到开关容量2,
如果两个灯状态不同或只控制一个灯,那么容量是1,表示一种互斥状态。

添加开关到它控制的灯的边,容量1;以及灯到汇,容量1。

网络流,如果流小于灯数,那么无解。

然后对于一个开关,如果他控制两个状态要求相同的灯或一盏灯,那么他的状态确定;如果他控制的两个灯要求不一样,那么进到网络流里面,看看从这开关出发的边流向哪个灯了,他的状态就是哪个灯要求的状态。

注意如果这个开关出发没有流,说明他没用,他对灯造不成影响。随便输出就好。

我的代码特别长,估计对状态的处理不太好吧。不过思路大概就是这样。


代码

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#define _ ios_base::sync_with_stdio(0);cin.tie(0);
using namespace std;

const int MAXN=1007;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
struct Dinic
{
    struct Edge
    {
        int from, to, cap, flow; //cap容量 flow流量
        Edge() {}
        Edge(int u, int v, int c, int f)
        {
            from=u;
            to=v;
            cap=c;
            flow=f;
        }
    } e[MAXN];
    vector<Edge> edges;  //顺序的插入边
    vector<int> G[MAXN]; //保存边号
    bool vis[MAXN];      //BFS使用
    int d[MAXN];
    int cur[MAXN];
    void init(int n)
    {
        for(int i=0; i < n; i++)
            G[i].clear();
        edges.clear();
    }

    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0)); //单向边第三个参数写0,双向边写cap
        int t_m=edges.size();
        G[from].push_back(t_m-2);
        G[to].push_back(t_m-1);
    }

    bool BFS(int s, int t)
    {
        memset(vis, 0, sizeof(vis));
        queue<int> Q;
        Q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!Q.empty())
        {
            int x=Q.front();
            Q.pop();
            for(int i=0; i < G[x].size(); i++)
            {
                Edge &e=edges[G[x][i]];
                if(!vis[e.to]&&e.cap > e.flow) //残量网络
                {
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int DFS(int x, int a, int s, int t)
    {
        if(x==t||a==0)
            return a;
        int flow=0, _f;
        for(int &i=cur[x]; i < G[x].size(); i++)
        {
            Edge &e=edges[G[x][i]];
            if(d[x]+1==d[e.to]&&(_f=DFS(e.to, min(a, e.cap-e.flow), s, t)) > 0)
            {
                e.flow+=_f;
                edges[G[x][i]^1].flow-=_f;
                flow+=_f;
                a-=_f;
                if(a==0)
                    break;
            }
        }
        return flow;
    }
    int Maxflow(int s, int t)
    {
        int flow=0;
        while(BFS(s, t))
        {
            memset(cur, 0, sizeof(cur));
            flow+=DFS(s, oo, s, t);
        }
        return flow;
    }
} dinic;
int sw[MAXN][5]; //1表示有一个要求on的 -1表示一个要求off的 2 -2表示两个 0表示1on1off
int main()
{
    _ int n, m;
    while(cin>>n)
    {
        cin>>m;
        dinic.init(1007);
        memset(sw, 0, sizeof(sw));
        for(int i=1; i<=n; i++)
        {
            int tn;
            cin>>tn;
            while(tn--)
            {
                int t;
                string s;
                cin>>t>>s;
                if(sw[t][0]==0)
                    sw[t][1]=(s[1]=='N' ? 1 : -1), sw[t][2]=i;
                else if(sw[t][0]==1||sw[t][0]==-1)
                    sw[t][3]=(s[1]=='N' ? 1 : -1), sw[t][4]=i;
                sw[t][0]+=(s[1]=='N' ? 1 : -1);
            }
        }
        const int sup_s=1001, sup_t=1002;
        for(int i=1; i<=m; i++)
        {
            if(sw[i][0]==0||sw[i][0]==1||sw[i][0]==-1)
                dinic.AddEdge(sup_s, i, 1);
            else
                dinic.AddEdge(sup_s, i, 2);
            if(sw[i][0]==0||sw[i][0]==2||sw[i][0]==-2)
                dinic.AddEdge(i, m+sw[i][2], 1), dinic.AddEdge(i, m+sw[i][4], 1);
            else
                dinic.AddEdge(i, m+sw[i][2], 1);
        }
        for(int i=1; i<=n; i++)
        {
            dinic.AddEdge(m+i, sup_t, 1);
        }
        int ma=dinic.Maxflow(sup_s, sup_t);
        if(ma < n)
            cout<<-1<<endl;
        else
        {
            for(int i=1; i<=m; i++)
            {
                if(sw[i][0]==2||sw[i][0]==1)
                    cout<<"ON"<<(i==m ? '\n' : ' ');
                else if(sw[i][0]==-2||sw[i][0]==-1)
                    cout<<"OFF"<<(i==m ? '\n' : ' ');
                else
                {
                    bool ff=0;
                    for(int kkk=0;kkk<dinic.G[i].size();kkk++)
                    {
                        int u=dinic.G[i][kkk];
                        if(dinic.edges[u].flow > 0)
                        {
                            ff=1;
                            if(dinic.edges[u].to==sw[i][2]+m)
                            {
                                cout<<(sw[i][1]==1 ? "ON" : "OFF")<<(i==m ? '\n' : ' ');
                                break;
                            }
                            else if(dinic.edges[u].to==sw[i][4]+m)
                            {
                                cout<<(sw[i][3]==1 ? "ON" : "OFF")<<(i==m ? '\n' : ' ');
                                break;
                            }
                        }

                    }
                    if(!ff)//这个开关没有流,那么开关与否无所谓
                    {
                        cout<<"ON"<<(i==m ? '\n' : ' ');
                    }
                }
            }
        }
    }
    //system("pause");
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值