链接:http://poj.org/problem?id=3683
题意:某一天,有N个活动,给出每个活动的开始结束时间。每个活动都需要牧师参与一段时间,牧师可以在开始或者最后的时间进行工作。问是否有满足的安排方式,输出一种。
思路:两种选择,只能选择一种,大概就是2-sat。建图:如果时间A和时间B冲突,就A->B',B->A',这样建边。然后2-sat判断是否有解。
区间相交:
bool conflict(int a,int la,int b,int lb){
if(b>=a&&b<a+la)return true;
if(a>=b&&a<b+lb)return true;
return false;
}
然后2-sat输出一组解。我原来的写法应该是错的,大体的流程是:
1.建反图,反图的原因是因为 原图叶子节点的限制最少,不需要考虑其他点。
2.建立新图的冲突关系,原来是i和i’冲突,需要在新图中重新标记,用vector存(原来用一维数组存感觉是不对的)
3.拓扑排序
4.染色,对于每个新染上色的点,都要把与他冲突的点染上相反的染色(我用1和-1)。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define mem(a,b) memset((a),(b),sizeof((a)))
#define For(i,a,b) for(int (i)=(a);(i) < (b);(i)++)
#define Ror(i,a,b) for(int (i)=(a);(i) > (b);(i)--)
#define mp make_pair
#define pb push_back
#define inf 0x3f3f3f3f
void RI (int& x){
x = 0;
char c = getchar ();
while (c == ' '||c == '\n') c = getchar ();
bool flag = 1;
if (c == '-'){
flag = 0;
c = getchar ();
}
while (c >= '0' && c <= '9'){
x = x * 10 + c - '0';
c = getchar ();
}
if (!flag) x = -x;
}
void RII (int& x, int& y){RI (x), RI (y);}
void RIII (int& x, int& y, int& z){RI (x), RI (y), RI (z);}
const int maxn = 2020;
int n,m;
struct Side{
int u,v,next;
}side[maxn*maxn];
int top,node[maxn];
int t,dfn[maxn],low[maxn],sum;
stack<int>s;
void add_side(int u,int v){
side[top] = (Side){u,v,node[u]};
node[u] = top++;
}
void init(){
memset(node,-1,sizeof(node));
memset(dfn,0,sizeof(dfn));
top=sum=t=0;
}
void dfs(int u){
dfn[u]=low[u]=++t;
s.push(u);
for(int i=node[u];i!=-1;i=side[i].next){
int v=side[i].v;
if(!dfn[v])dfs(v);
if(dfn[v]!=-1)low[u]=min(low[u],low[v]);
}
if(low[u]==dfn[u]){
int v;
do{
v=s.top();s.pop();
dfn[v]=-1;
low[v]=sum;
}while(v!=u);
sum++;
}
}
bool solve(){
for(int i=0;i<n;i++)//判断是否有可行解
if(low[2*i]==low[2*i+1])return false;
return true;
}
struct NN{
int ta,tb,last;
}nn[maxn];
int col[maxn];
int in[maxn];
queue<int>q;
vector<int>v[maxn];
void paint(int u){//cout<<u<<' ';
int siz = v[u].size();
For(i,0,siz){
if(col[v[u][i]] == 0){
col[v[u][i]] = col[u]*(-1);
paint(v[u][i]);
}
}
}
void ppp(){
mem(col,0);
For(i,0,2*n)v[i].clear();
For(i,0,n){
v[low[2*i]].pb(low[2*i+1]);
v[low[2*i+1]].pb(low[2*i]);
}
int tmp = top;
mem(node,-1);
For(i,0,tmp){
if(low[side[i].v] == low[side[i].u])continue;
add_side(low[side[i].v],low[side[i].u]);
in[low[side[i].u]] ++;
}
For(i,0,sum){
if(in[i] == 0)q.push(i);
}
while(!q.empty()){
int u = q.front();
q.pop();
for(int i = node[u];i != -1;i = side[i].next){
int v = side[i].v;
in[v] --;
if(!in[v])q.push(v);
}
if(col[u] == 0){
col[u] = 1;
paint(u);
}
}
For(i,0,n){
if(col[low[2*i]] == 1){
printf("%02d:%02d %02d:%02d\n", nn[i].ta/60,nn[i].ta%60,(nn[i].ta+nn[i].last)/60,(nn[i].ta+nn[i].last)%60);
}
else {
printf("%02d:%02d %02d:%02d\n", nn[i].tb/60,nn[i].tb%60,(nn[i].tb+nn[i].last)/60,(nn[i].tb+nn[i].last)%60);
}
}
}
bool conflict(int a,int la,int b,int lb){
if(b>=a&&b<a+la)return true;
if(a>=b&&a<b+lb)return true;
return false;
}
int main()
{
//freopen("test.txt","r",stdin);
while(~scanf("%d",&n)){
For(i,0,n){
int ha,ma,hb,mb,last;
scanf("%d:%d %d:%d %d",&ha,&ma,&hb,&mb,&last);
int ta = ha*60+ma,tb = hb*60+mb-last;
nn[i] = (NN){ta,tb,last};
}
init();
For(i,0,n){
For(j,i+1,n){
if(i == j)continue;
if(conflict(nn[i].ta,nn[i].last,nn[j].ta,nn[j].last)){
add_side(2*i,2*j+1);
add_side(2*j,2*i+1);//cout<<i<<j<<0<<endl;
}
if(conflict(nn[i].tb,nn[i].last,nn[j].ta,nn[j].last)){
add_side(2*i+1,2*j+1);
add_side(2*j,2*i);//cout<<i<<j<<1<<endl;
}
if(conflict(nn[i].ta,nn[i].last,nn[j].tb,nn[j].last)){
add_side(2*i,2*j);
add_side(2*j+1,2*i+1);//cout<<i<<j<<3<<endl;
}
if(conflict(nn[i].tb,nn[i].last,nn[j].tb,nn[j].last)){
add_side(2*i+1,2*j);
add_side(2*j+1,2*i);//cout<<i<<j<<4<<endl;
}
}
}
For(i,0,2*n){
if(!dfn[i])dfs(i);
}
if(solve() == 0)puts("NO");
else {
puts("YES");
ppp();
}
}
return 0;
}