题意:
一个小镇里面只有一个牧师,现在有些新人要结婚,需要牧师分别去主持一个仪式,给出每个婚礼的开始时间 s 和结束时间 t ,还有该场婚礼的仪式需要进行的时间d(每对新人需要的时间长短可能不同),仪式只能在婚礼刚开始或者剩余d时间结束时进行,即仪式只能在[s, s+d]时间段内或者在[t-d, d]时间段内进行。问能否给出一种安排,使牧师能够完成所有新人婚礼的仪式,如果可以,输出一种安排。
思路:
明显的2-SAT问题,每场婚礼只有两个举行仪式的时间,然后每个元素之间的冲突就是该场婚礼的一个时间元素与其它婚礼建的时间元素重叠(另外,认为08:00-08:30与08:30-09:00也是重叠的),图的时候需要注意。之后便可以利用两个模板进行求解了。
Code:
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn = 1005*2;
const int maxm = maxn*maxn;
struct node
{
int u, v, next;
} edge[maxm], new_edge[maxm];
int head[maxn];
int n, no, new_no;
char s[maxn][2][10];
int tim[maxn][2], limit[maxn];
int index, top;
int dfn[maxn], low[maxn], stack[maxn], vis[maxn];
int cnt;
int belong[maxn];
queue<int> q;
int opp[maxn], deg[maxn], color[maxn];
inline void init()
{
no = 0;
memset(head, -1, sizeof head);
index = top = 0;
memset(dfn, 0, sizeof dfn);
memset(vis, 0, sizeof vis);
new_no = 0;
memset(deg, 0, sizeof deg);
memset(color, 0, sizeof color);
}
inline void add(int u, int v)
{
edge[no].u = u, edge[no].v = v;
edge[no].next = head[u]; head[u] = no++;
}
inline void new_add(int u, int v)
{
new_edge[new_no].u = u, new_edge[new_no].v = v;
new_edge[new_no].next = head[u]; head[u] = new_no++;
}
void mapping()
{
int hh, mm, minn, maxx;
scanf("%d", &n); init();
for(int i = 0; i < n; ++i)
{
scanf("%s %s %d", s[i][0], s[i][1], &limit[i]);
hh = (s[i][0][0]-'0')*10+(s[i][0][1]-'0');
mm = (s[i][0][3]-'0')*10+(s[i][0][4]-'0');
tim[i][0] = hh*60+mm;
hh = (s[i][1][0]-'0')*10+(s[i][1][1]-'0');
mm = (s[i][1][3]-'0')*10+(s[i][1][4]-'0');
tim[i][1] = hh*60+mm;
}
for(int i = 0; i < n; ++i)
for(int j = i+1; j < n; ++j)
{
minn = min(tim[i][0], tim[j][0]);
maxx = max(tim[i][0]+limit[i], tim[j][0]+limit[j]);
if(maxx-minn < limit[i]+limit[j])
{
add(i*2, j*2+1);
add(j*2, i*2+1);
}
minn = min(tim[i][0], tim[j][1]-limit[j]);
maxx = max(tim[i][0]+limit[i], tim[j][1]);
if(maxx-minn < limit[i]+limit[j])
{
add(i*2, j*2);
add(j*2+1, i*2+1);
}
minn = min(tim[i][1]-limit[i], tim[j][1]-limit[j]);
maxx = max(tim[i][1], tim[j][1]);
if(maxx-minn < limit[i]+limit[j])
{
add(i*2+1, j*2);
add(j*2+1, i*2);
}
minn = min(tim[i][1]-limit[i], tim[j][0]);
maxx = max(tim[i][1], tim[j][0]+limit[j]);
if(maxx-minn < limit[i]+limit[j])
{
add(i*2+1, j*2+1);
add(j*2, i*2);
}
}
}
void tarjan(int cur)
{
dfn[cur] = low[cur] = ++index;
stack[++top] = cur; vis[cur] = 1;
for(int k = head[cur]; k != -1; k = edge[k].next)
{
if(!dfn[edge[k].v])
{
tarjan(edge[k].v);
low[cur] = min(low[cur], low[edge[k].v]);
}
else if(vis[edge[k].v])
{
low[cur] = min(low[cur], dfn[edge[k].v]);
}
}
if(dfn[cur] == low[cur])
{
++cnt;
do
{
vis[stack[top]] = 0;
belong[stack[top]] = cnt;
--top;
}
while(stack[top+1] != cur);
}
}
void topsort()
{
memset(head, -1, sizeof head);
for(int i = 0; i < no; ++i)
{
int u = edge[i].u, v = edge[i].v;
if(belong[u] == belong[v]) continue;
new_add(belong[v], belong[u]);
++deg[belong[u]];
}
while(!q.empty()) q.pop();
for(int i = 1; i <= cnt; ++i) if(!deg[i]) q.push(i);
while(!q.empty())
{
int u = q.front(); q.pop();
if(!color[u]) color[u] = 1, color[opp[u]] = -1;
int k = head[u];
while(k != -1)
{
if(--deg[new_edge[k].v] == 0) q.push(new_edge[k].v);
k = new_edge[k].next;
}
}
}
void print()
{
puts("YES");
for(int i = 0; i < n; ++i)
{
if(color[belong[i*2]] == 1)
{
int mm = tim[i][0]+limit[i];
printf("%s %02d:%02d\n", s[i][0], mm/60, mm%60);
}
if(color[belong[i*2+1]] == 1)
{
int mm = tim[i][1]-limit[i];
printf("%02d:%02d %s\n", mm/60, mm%60, s[i][1]);
}
}
}
void solve()
{
for(int i = 0; i < n*2; ++i)
if(!dfn[i]) tarjan(i);
for(int i = 0; i < n; ++i)
{
if(belong[i*2] == belong[i*2+1])
{
puts("NO");
return ;
}
else
{
opp[belong[i*2]] = belong[i*2+1];
opp[belong[i*2+1]] = belong[i*2];
}
}
topsort();
print();
}
int main()
{
mapping();
solve();
return 0;
}
继续加油~