2011.08.07

2-SAT模板

#include <iostream>
#include <vector>
#include <stack>
using namespace std;

const int MAXN = 61;
vector<int> g[MAXN] , gt[MAXN] , tree[MAXN];         // g正图 , gt 逆图 , tree缩点逆图
int n , m , cnt , ID , id[MAXN] , tree_cnt , order[MAXN] , indegree[MAXN] , color[MAXN];
bool used[MAXN] , used_tree[MAXN][MAXN];

void init()
{
        for(int i=0; i < 2*n; i++) {
                g[i].clear();
                gt[i].clear();
        }
}

void build_graph()// 建图,i << 1 与 (i << 1) + 1 相斥
{
        int u , v , uu , vv ;
        char c1 , c2;
        for(int i=0; i < m; i++){
                scanf( "%d%c %d%c" , &u , &c1 , &v , &c2 );
                if(c1 == 'w'){
                        u = u * 2;
                        uu = u + 1;
                }
                else{
                        u = 2 * u + 1;
                        uu = u - 1;
                }
                if(c2 == 'w'){
                        v = 2 * v;
                        vv = v + 1;
                }
                else{
                        v = 2 * v + 1;
                        vv = v - 1;
                }
                g[u].push_back( vv );
                gt[vv].push_back( u );
                g[v].push_back( uu );
                gt[uu].push_back( v );
        }
        g[0].push_back( 1 );
        gt[1].push_back( 0 );
}

void dfs1( int u )
{
        vector<int>::iterator v;
        used[u] = true;
        for(v = g[u].begin(); v != g[u].end(); v++)
                if(!used[*v])
                        dfs1(*v);
        order[cnt++] = u;
}

void dfs2( int u )
{
        vector<int>::iterator v;
        used[u] = true;
        id[u] = ID;
        for(v = gt[u].begin(); v != gt[u].end(); v++)
                if(!used[*v])
                        dfs2(*v);
}

void scc() // 缩点 
{
        memset(used , 0 , sizeof(used));
        cnt = 0;
        for(int i=0; i < 2*n; i++)
                if(!used[i])
                        dfs1(i);
        memset(used , 0 , sizeof(used));
        ID = 0;
        for(int i=cnt - 1; i >= 0 ; i--)
                if(!used[ order[i] ]){
                        ID ++;
                        dfs2( order[i] );
                }
}

bool sat_judge()  //2-sat判定
{
        for(int i=0; i < 2*n; i+=2)
                if(id[i] == id[i+1])
                        return false;  //无解
        return true;
}

void build_tree()  //缩点成树 , 建立逆图
{
        memset(used_tree , 0 , sizeof(used_tree));
        memset(indegree , 0 , sizeof(indegree));
        for(int i=1; i <= ID; i++) tree[i].clear();
        for(int i=0; i < 2*n; i++)
                for(vector<int>::iterator j=g[i].begin(); j != g[i].end(); j++)
                        if(!used_tree[ id[*j] ][ id[i] ] && id[*j] != id[i]) {
                                indegree[ id[i] ] ++;
                                tree[ id[*j] ].push_back( id[i] );
                                used_tree[ id[*j] ][ id[i] ] = true;
                        }
}

void topsort()//拓扑排序
{
        stack<int> S;
        for(int i=1; i <= ID; i++)
                if(indegree[i] == 0)
                        S.push( i );
        tree_cnt = 0;
        while( !S.empty() ) {
                int u = S.top();
                S.pop();
                order[ tree_cnt ++ ] = u;  //记录反向拓扑排序的序列
                vector<int>::iterator v;
                for(v = tree[u].begin(); v != tree[u].end(); v++) {
                        indegree[*v] --;
                        if(indegree[*v] == 0)
                                S.push( *v );
                }
        }
}

void dfs_tree( int u )
{
        vector<int>::iterator v;
        color[u] = 2;
        for(v = tree[u].begin(); v != tree[u].end(); v++) 
                if(!color[*v])
                        dfs_tree(*v);
}

void tree_color()//对树进行染色
{
        memset(color , 0 , sizeof(color));
        for(int i=0; i < tree_cnt; i++)
                if(!color[ order[i] ]){
                        color[ order[i] ] = 1;
                        for(int j=0; j < 2*n; j++) {
                                if(id[j] == order[i]) {
                                        int tmp ;
                                        if(j & 1) tmp = j - 1;
                                        else tmp = j + 1;
                                        tmp = id[ tmp ];
                                        if(color[tmp]) continue;
                                        color[tmp] = 2;
                                        dfs_tree( tmp );//对前向边染色
                                }
                        }
                }
}

void answer()
{
        int sign = color[ id[0] ]; //得出结果
        bool flag = true;
        for(int i=2; i < n*2; i++){
                if(color[id[i]] == sign){
                        if(!flag) printf(" ");
                        if(i & 1) printf( "%dh" , i >> 1 );
                        else printf( "%dw" , i >> 1 );
                        flag = false;
                }
        }
        puts("");
}

void solve()
{
        build_graph();
        scc();
        if(!sat_judge()){ puts("bad luck"); return; }
        build_tree();
        topsort();
        tree_color();
        answer();
}

int main()
{
        while(scanf("%d %d" , &n , &m ) != EOF) {
                if(n == 0 && m == 0) break;
                init();
                solve();
        }
        return 0;
}


CF#80div2

A.水题。

B.水题。数列求和。

C.有一个环,找以环上的为根的树。如果不是这种情况则输出NO,注意图有可能不连通,缅怀一下再次挂掉的今神……

#include<cstdio>
#include<cstring>
using namespace std;
const int N=200;
const int inf=1<<29-1;
int dis[N][N];//用来记录最短路径
int g[N][N];//记录边的情况
int pre[N][N];//记录从i到j的最后的一个中间节点
int path[N];//记录最小环
int cnt,m,n,mmin;//最小环的顶点数
bool vis[N],cir[N];
void floyd()
{
    mmin=inf;
    for(int k=0;k<n;k++)
    {
        for(int i=0;i<k;i++)
            for(int j=i+1;j<k;j++)
            {
                if(mmin>dis[i][j]+g[k][i]+g[k][j])
                {
                    mmin=dis[i][j]+g[k][i]+g[k][j];
                    cnt=0;
                    int p=j;
                    while(p!=i)      //逆向寻找前驱结点直到找到最前面的i。i->…->j
                    {
                        path[cnt++]=p;
                        p=pre[i][p];
                    }
                    path[cnt++]=i;
                    path[cnt++]=k;
                }
            }
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            {
                if(dis[i][j]>dis[i][k]+dis[k][j])
                {
                    dis[i][j]=dis[i][k]+dis[k][j];
                    pre[i][j]=pre[k][j];//自己好好根据注释好好理一下。
                }
            }
    }
}
bool dfs(int s,int ss)
{
    vis[s]=1;
    for(int i=0;i<n;i++)if(i!=ss && g[s][i]<inf){
        if(vis[i] && ss==-1) continue;
        if(vis[i] || dfs(i,s)==0) return false;
    }
    return true;
}
int main()
{
    //freopen("in","r",stdin);
    //freopen("out","w",stdout);
    int i,j,k,u,v;
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++)
        for(j=0;j<n;j++){
            pre[i][j]=i;
            g[i][j]=inf;
            dis[i][j]=inf;
        }
    for(i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        g[u-1][v-1]=g[v-1][u-1]=dis[u-1][v-1]=dis[v-1][u-1]=1;
    }
    floyd();
    if(mmin==inf){
        printf("NO\n");
        return 0;
    }
    for(i=0;i<cnt;i++) cir[path[i]]=vis[path[i]]=1;
    for(i=0;i<cnt;i++)
       if(dfs(path[i],-1)==0){
        printf("NO\n");
        return 0;
       }
    for(i=0;i<n;i++) if(vis[i]==0){
        printf("NO\n");return 0;
    }
    printf("FHTAGN!\n");
    return 0;
}

        说毛啊今天连个模版题都没交成,心情抑郁……

        还有我说codeforces你敢不敢让我把源文件加上去?不过在这种烂网速下面淡定的没掉rating充分说明我以前那个rating是有多菜,当然现在也一样…仰望hzhua大神陡增的曲线,只想说你还差的远呢…有多远呢,如果秒速5厘米,那中间可能横亘了7年以上。

        明天去听梁神的网络流ORZ,期待中…所以要睡觉,真奇怪,为什么你老是要睡觉?


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值