【数字_ID】CUC-SpringTraining-16

HDU3062Party

2-SAT的模板题。建边的时候注意对称性。如果a和b矛盾,那么a->b’,b->a’

#include <iostream>
#include <string>
#include <stack>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int maxn = 10000;
const int maxm = 2000200;

int head[maxn],instack[maxn],id[maxn],low[maxn] , dfn[maxn];
int ct , idx;
int tot;
int a1,a2,b1,b2;
int n,m;
stack<int>S;
void init(int n)
{
	ct = idx = tot = 0;;
	while(!S.empty())S.pop();
	for(int i = 0;i<=2*n;i++){
		head[i] = -1;
		instack[i] = 0;
		dfn[i] = low[i] = 0;
	}	
}

struct _edge{
	int v;
	int next;
}edge[maxm];


void addedge(int u,int v)
{
	edge[ct].v = v;
	edge[ct].next = head[u];
	head[u] = ct++;
}


void tar(int now)
{
	dfn[now] = low[now] = ++idx;
	S.push(now);
	instack[now] = 1;
	for(int i = head[now];~i;i = edge[i].next)
	{
		int to = edge[i].v;
		if(!dfn[to]){
			tar(to);
			low[now] = min(low[now],low[to]);
		}else if(instack[to]){
			low[now] = min(low[now] , dfn[to]);	
		}
	}
	if(low[now] == dfn[now])
	{
		tot ++;
		while(S.top() != now)
		{
			id[S.top()] = tot;
			instack[S.top()] = 0;
			S.pop();
		}
		id[now] = tot;
		instack[now] = 0;
		S.pop();
	}
}


int main()
{
	while(~scanf("%d%d",&n,&m))
	{

		init(n);
		for(int i = 0;i<m;i++)
		{
			scanf("%d%d%d%d",&a1,&a2,&b1,&b2);
			int u1 = 2*a1 + b1;
			int v1 = 2*a2 + 1 - b2;
			int u2 = 2*a2 + b2;
			int v2 = 2*a1 + 1 - b1;
			addedge(u1,v1);
//			addedge(v1,u1);
			addedge(u2,v2);
//			addedge(v2,u2);
		}
		for(int i = 0;i<2*n;i++)
		{
			if(!dfn[i]){
				tar(i);
			}	
		}
		bool flag = true;
		for(int i = 0;i<n;i++)
		{
			if(id[2*i] == id[2*i + 1]){
				flag = false;
				break;
			}
		}
		if(flag)printf("YES\n");
		else printf("NO\n");
	}
	
}

POJ3683

每场婚礼只能选两个时间点,问能不能找出一种安排,使得每场都参加,且时间点不冲突。
2-SAT,需要 n 2 n^{2} n2找出哪些时间点之间是矛盾的,根据矛盾关系渐边,然后2SAT,将缩点后标号小的输出。

#include <iostream>
#include <stack>
#include <algorithm>
#include <stdio.h>


using namespace std;

const int maxn = 10020;

const int maxm = 32000020;

int head[maxn],instack[maxn],id[maxn] , low[maxn] , dfn[maxn];
int ct , tot , idx;
int n,m;
int aa,bb,cc,dd,ee;
stack<int>S;
struct _edge{
    int v;
    int next;
}edge[maxm];

void init(int n)
{
    while(!S.empty())S.pop();
    ct = tot = idx = 0;
    for(int i = 0;i<=n;i++)
    {
        head[i] = -1;
        instack[i] = id[i] = dfn[i] = low[i] = 0;
    }
}

void addedge(int u,int v)
{
    edge[ct].v = v;
    edge[ct].next = head[u];
    head[u] = ct++;
}

void tar(int now)
{
    low[now] = dfn[now] = ++idx;
    S.push(now);
    instack[now] = true;
    for(int i = head[now];~i;i = edge[i].next)
    {
        int to = edge[i].v;
        if(!dfn[to]){
            tar(to);
            low[now] = min(low[now] , low[to]);
        }else if(instack[to])
        {
            low[now] = min(low[now] , dfn[to]);
        }
    }
    if(low[now] == dfn[now])
    {
        ++tot;
        while(S.top()!=now)
        {
            id[S.top()] = tot;
            instack[S.top()] = false;
            S.pop();
        }
        id[S.top()] = tot;
        instack[S.top()] = false;
        S.pop();
    }
}

struct te{
    int St;
    int Et;
    int w;
}Te[maxm];

bool check(te ati , te bti)
{
    if(min(ati.Et , bti.Et) > max(ati.St , bti.St))return false;
    return true;
}

int main()
{
    while(~scanf("%d",&n))
    {
        init(2*n);
        for(int i = 0;i<n;i++)
        {
            scanf("%d:%d%d:%d%d",&aa,&bb,&cc,&dd,&ee);
            Te[2*i].St = aa *60 + bb ;
            Te[2*i].Et = aa * 60 + bb +ee;
            Te[2*i + 1].St = cc * 60 + dd - ee;
            Te[2*i + 1].Et = cc * 60 + dd;
            Te[2*i].w = Te[2*i + 1].w = ee;
        }
        for(int i = 0;i<n;i++){
            for(int j = i + 1;j<n;j++){
                if(!check(Te[2*i] , Te[2*j])){
                    addedge(2*i , 2*j + 1);
                    addedge(2*j , 2*i + 1);
                }
                if(!check(Te[2*i] , Te[2*j + 1])){
                    addedge(2*i , 2*j);
                    addedge(2*j + 1,2*i+1);
                }
                if(!check(Te[2*i+1] , Te[2*j])){
                    addedge(2*i+1 , 2*j+1);
                    addedge(2*j , 2*i);
                }
                if(!check(Te[2*i+1],Te[2*j+1])){
                    addedge(2*i+1 , 2*j);
                    addedge(2*j+1 , 2*i);
                }
            }
        }
        for(int i = 0;i<2*n;i++)
        {
            if(!dfn[i]){
                tar(i);
            }
        }

        bool flag = true;
        for(int i = 0;i<n;i++)
        {
            if(id[2*i] == id[2*i + 1]){
                flag = false;
                break;
            }
        }
        if(!flag){
            printf("NO\n");
            continue;
        }
        printf("YES\n");
        for(int i = 0;i<n;i++)
        {
            if(id[2*i] < id[2*i+1]){
                printf("%02d:%02d %02d:%02d\n" , Te[2*i].St/60 , Te[2*i].St % 60 , Te[2*i].Et / 60 , Te[2*i].Et % 60);
            }else{
                printf("%02d:%02d %02d:%02d\n" , Te[2*i+1].St/60 , Te[2*i+1].St % 60 , Te[2*i+1].Et / 60 , Te[2*i+1].Et % 60);
            }
        }
    }

}

Wormholes 虫洞 HYSBZ - 1715

spfa判环,没啥说的。

#include <iostream>
#include <queue>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1020;
const int maxm = 10020;

int head[maxn] , cnt[maxn] , inq[maxn] , dis[maxn];
int ct;
struct _edge{
    int v;
    int w;
    int next;
}edge[maxm];

void addedge(int u,int v ,int w)
{
    edge[ct].v = v;
    edge[ct].w = w;
    edge[ct].next = head[u];
    head[u] = ct++;
}
void init(int n)
{
    for(int i = 0;i<=n;i++){
        head[i] = -1;
        cnt[i] = 0;
        inq[i] = 0;
        dis[i] = INF;
    }
    ct = 0;
}
int n,m,mm,u,v,w,aa,bb,cc;


bool spfa(int st)
{
    queue<int>Q;
    Q.push(st);
    inq[st] = true;
    cnt[st] = 1;
    dis[st] = 0;
    while(!Q.empty())
    {
        int now = Q.front();
        Q.pop();
        inq[now] = false;
        for(int i = head[now];~i;i = edge[i].next)
        {
            int to = edge[i].v;
            if(dis[to] > dis[now] + edge[i].w )
            {
                dis[to] = dis[now] + edge[i].w;
                if(!inq[to]){
                    Q.push(to);
                    inq[to] = true;
                    cnt[to]++;
                    if(cnt[to] > n)return false;
                }
            }
        }
    }
    return true;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&mm);
        init(n);
        for(int i = 0;i<m;i++){
            scanf("%d%d%d" , &u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        for(int i = 0;i<mm;i++){
            scanf("%d%d%d" , &u,&v,&w);
            addedge(u,v,-w);
        }
        if(spfa(1)){
            printf("NO\n");
        }else{
            printf("YES\n");
        }
    }


}

糖果 HYSBZ - 2330

一道非常经典的查分约束,我用的最长路,得到的是满足条件的最小值。同时要记得加每个糖果大于0的约束。
可以好好做一下,包含了各种可能,以后差分约束的裸题都不怕对了。

#include <iostream>
#include <stack>
#include <algorithm>
#include <stdio.h>
#include <queue>
#define INF 0x3f3f3f3f
#define ll long long

using namespace std;

const int maxn = 100020;

const int maxm = 320020;

int head[maxn] , cnt[maxn] ;
ll dis[maxn];
bool inq[maxn];
int ct , tot , idx;
int n,m,k;
int aa,bb,cc,dd,ee;

struct _edge{
    int v;
    ll w;
    int next;
}edge[maxm];

void init(int n)
{
    ct  = 0;
    for(int i = 0;i<=n;i++)
    {
        head[i] = -1;
        dis[i] = -INF;
        cnt[i] = 0;
        inq[i] = 0;
    }
}

void addedge(int u,int v,ll w)
{
    edge[ct].v = v;
    edge[ct].w = w;
    edge[ct].next = head[u];
    head[u] = ct++;
}

bool spfa(int now)
{
    queue<int>Q;
    dis[now] = 0ll;
    for(int i = 1;i<=n;i++)Q.push(i) , dis[i] = 1ll , inq[i] = true , cnt[i] = 1;
    while(!Q.empty())
    {
        int t = Q.front();
        Q.pop();
        inq[t] = false;
        cnt[t]++;
        for(int i = head[t];~i;i = edge[i].next)
        {
            int to = edge[i].v;
            if(dis[to] < dis[t] + edge[i].w)
            {
                dis[to] = edge[i].w + dis[t];
                if(!inq[to])
                {
                    Q.push(to);
                    inq[to] = true;
                    cnt[to]++;
                    if(cnt[to] > n+2)return false;
                }
            }
        }
    }
    return true;
}

int main()
{
    scanf("%d%d",&n,&k);
    init(n);
    for(int i = 0;i<k;i++)
    {
        scanf("%d%d%lld",&aa,&bb,&cc);
        if(aa == 1){
            addedge(bb,cc,0);
            addedge(cc,bb,0);
        }else if(aa == 2){
            if(bb == cc){
                printf("-1\n");
                return 0;
            }
            addedge(bb,cc,1);
        }else if(aa == 3){
            addedge(cc,bb,0);
        }else if(aa == 4){
            if(bb == cc){
                printf("-1\n");
                return 0;
            }
            addedge(cc,bb,1);
        }else if(aa == 5){
            addedge(bb,cc,0);
        }
    }
    for(int i = 1;i<=n;i++)addedge(0,i,1);
    if(spfa(0))
    {
        ll sum = 0;
        for(int i = 1;i<=n;i++)sum += dis[i];
        printf("%lld\n",sum);
    }
    else
    {
        printf("-1\n");
    }

}

POJ 1364 King

给你一些连续序列的和的限制,问你能不能找到满足限制的序列情况
比如 a i + a i + 1 + . . . + a j − 1 + a j &gt; k a_{i}+a_{i+1}+...+a_{j-1}+a_{j} &gt; k ai+ai+1+...+aj1+aj>k,我们考虑其前缀和序列 p r e [ i ] pre[i] pre[i],刚才的限制其实就是 p r e [ j ] − p r e [ i − 1 ] &gt; k pre[j] - pre[i-1] &gt; k pre[j]pre[i1]>k,也就变成了一道差分约束的题

#include <iostream>
#include <string>
#include <stack>
#include <algorithm>
#include <stdio.h>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 10000;
const int maxm = 2000200;

int head[maxn];
int ct;
int m,n;
int dis[maxn] , cnt[maxn];
bool inq[maxn];
void init(int n)
{
	for(int i = 0;i<=n;i++){
		head[i] = -1;
		dis[i] = INF;
		cnt[i] = 0;
		inq[i] = false;
	}
	ct = 0;
}

struct _edge{
	int v;
	int w;
	int next;
}edge[maxm];

void addedge(int u,int v,int w)
{
	edge[ct].v = v;
	edge[ct].w = w;
	edge[ct].next = head[u] ;
	head[u] = ct++;
}

bool spfa()
{
	queue<int>Q;
	for(int i = 0;i<=n;i++)
	{
		inq[i] = true;
		cnt[i] = 1;
		dis[i] = 1;
		Q.push(i);
	}
	while(!Q.empty())
	{
		int now = Q.front();
		Q.pop();
		inq[now] = false;
		for(int i = head[now];~i;i = edge[i].next)
		{
			int to = edge[i].v;
			if(dis[to] > dis[now] + edge[i].w)
			{
				dis[to] = dis[now] + edge[i].w;
				if(!inq[to]){
					inq[to] = true;
					Q.push(to);
					cnt[to] ++;
					if(cnt[to] > n )return false;
				}
			}
		}
	}
	return true;
}

char ts[5];
int aa,bb,cc;
int main()
{
	while(~scanf("%d",&n) && n)
	{
		scanf("%d",&m);
		init(n);
		for(int i = 0;i<m;i++)
		{
			//cout << "fuck" << endl;
			scanf("%d %d %s %d",&aa,&bb,ts,&cc);
			if(ts[0] == 'g')
			{
				addedge(aa + bb , aa-1 , -cc - 1);
			}else{
				addedge(aa-1 , aa + bb , cc - 1);
			}
		}
		if(!spfa()){
			printf("successful conspiracy\n");
		}
		else{
			printf("lamentable kingdom\n");
		}
		
	}
}

HDU 2063 过山车

二分图最大匹配

#include <iostream>
#include <stack>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <string>
#include <queue>
#define INF 0x3f3f3f3f
#define ll long long

using namespace std;

const int maxn = 1020;

const int maxm = 10020;

int head[maxn];
int vis[maxn];
int matching[maxn];
int ct , tot , idx;
int n,m,k;
int aa,bb,cc,dd,ee;
int u,v;
struct _edge{
    int v;
    int w;
    int next;
}edge[maxm];

void init(int n)
{
    ct  = 0;
    for(int i = 0;i<=n;i++)
    {
        head[i] = matching[i] = -1;
        vis[i] = 0;
    }
}

void addedge(int u,int v)
{
    edge[ct].v = v;
    edge[ct].next = head[u];
    head[u] = ct++;
}

bool findp(int now)
{
    for(int i = head[now];~i;i = edge[i].next)
    {
        int to = edge[i].v;
        if(!vis[to])
        {
            vis[to] = true;
            if(matching[to] == -1 || findp(matching[to]))
            {
                matching[now] = to;
                matching[to] = now;
                return true;
            }
        }
    }
    return false;
}

int hung(int n)
{
   int ans = 0;
   for(int i = 1;i <= n ;i++)
   {
       if(matching[i] == -1){
            memset(vis,0,sizeof(vis));
            if(findp(i))ans++;
       }
   }
   return ans;
}


int main()
{
    while(~scanf("%d",&k) && k)
    {
        scanf("%d%d" , &m,&n);
        init(m + n);
        for(int i = 0;i<k;i++){
            scanf("%d%d",&u,&v);
            addedge(u,v+m);
    

Asteroids POJ - 3041

矩阵中有许多星球,每次可以扎一行或者炸一列,问至少要炸多少次可以炸了所有星球

考虑行列建图,对于任何一个星球,行代表的点和列代表的点之间见一个图,这条边就是这个星球,炸了这个星球只需要覆盖这条边的其中一个点即可。我们要做的就是选取尽可能少的点,覆盖所有边。

那么就是一个求最小点覆盖的题,数量同最大匹配。

#include <iostream>
#include <string>
#include <string>
#include <string.h>
#include <stack>
#include <algorithm>
#include <stdio.h>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 250020;
const int maxm = 200020;

int head[maxn];
int ct;
int m,n;
int aa,bb;
int vis[maxn] , cnt[maxn];
int matching[maxn];
void init(int n)
{
	for(int i = 0;i<=n;i++){
		head[i] = -1;
		matching[i] = -1;
	}
	ct = 0;
}

struct _edge{
	int v;
	int w;
	int next;
}edge[maxm];

void addedge(int u,int v)
{
	edge[ct].v = v;
	edge[ct].next = head[u] ;
	head[u] = ct++;
}

bool findp(int now)
{
	for(int i = head[now];~i;i = edge[i].next)
	{
		int to = edge[i].v;
		if(!vis[to])
		{
			vis[to] = true;
			if(matching[to] == -1 || findp(matching[to])){
				matching[now] = to;
				matching[to] = now;
				return true;
			}
		}
	}
	return false;
}

int hung()
{
	int ans = 0;
	for(int i = 1;i<=2*n;i++)
	{
		if(matching[i] == -1){
			memset(vis,0,sizeof(vis));
			if(findp(i))ans++;
		}
	}
	return ans;
}


int main()
{
	while(~scanf("%d%d" , &n,&m))
	{
		init(n * n);
		for(int i = 0;i<m;i++)
		{
			scanf("%d%d",&aa,&bb);
			addedge(aa , bb + n);
			addedge(bb+n , aa);
		}
		printf("%d\n" , hung());
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值