Bomb Game
题目大意:给出了n对坐标,每一对坐标选出一个放置炸弹,炸弹的半径可以控制,但是不能有相交的情况。求最大半径。
解题思路:二分+2sat 二分半径,用2sat判断当前情况是否回出现矛盾。出现矛盾的情况即一个集合里的两个元素同时被选择。
构图:添加对称边.
枚举
#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define N 220
int X[N],Y[N];
struct node
{
int to,nt;
}g[N*N*2];
int n;
int tot,top;
int s[N];
int head[N],mark[N];
void addedg(int x,int y)
{
g[tot].to=y;
g[tot].nt=head[x];
head[x]=tot++;
}
void init()
{
tot=0,top=0;
memset(head,-1,sizeof(head));
memset(mark,false,sizeof(mark));
}
double dist(int i,int j)
{
double dx=(X[i]-X[j])*(X[i]-X[j])*1.0;
double dy=(Y[i]-Y[j])*(Y[i]-Y[j])*1.0;
return sqrt(dx+dy);
}
void creat(double m)
{
for(int i=0;i<2*n;i++)
{
for(int j=i+1;j<2*n;j++)
{
if((i>>1)!=(j>>1))
{
if(dist(i,j)<m*2)
{
addedg(i,j^1);
addedg(j,i^1);
}
}
}
}
}
bool dfs(int u)
{
if(mark[u^1])return false;
if(mark[u]) return true;
mark[u]=true;
s[++top]=u;
for(int i=head[u];i+1;i=g[i].nt)
{
int v=g[i].to;
if(!dfs(v))return false;
}
return true;
}
bool check( )
{
memset(mark,false,sizeof(mark));
for(int i=0;i<2*n;i+=2)
{
if(!mark[i]&&!mark[i+1])
{
top=0;
if(!dfs(i))
{
while(top)mark[s[top--]]=false;
if(!dfs(i+1)) return false;
}
}
}
return true;
}
int main()
{
while(scanf("%d",&n)!=EOF){
rep(i,0,2*n-1)scanf("%d%d",&X[i],&Y[i]);
double l=0;
double r=9999999;
while(r-l>=1e-6)
{
double m=(l+r)*0.5;
init();
creat(m);
if(check( ))l=m;
else r=m;
}
printf("%.2f\n",r);
}
return 0;
}
缩点
#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define N 220
int X[N],Y[N];
struct node
{
int to,nt;
}g[N*N*2];
int n;
int tot,top;
int s[N];
int head[N],mark[N];
int bel[N],df[N];
int cnt,clo;
stack<int>S;
void addedg(int x,int y)
{
g[tot].to=y;
g[tot].nt=head[x];
head[x]=tot++;
}
void init()
{
tot=0,top=0;
cnt=0,clo=0;
memset(bel,0,sizeof(bel));
memset(df,0,sizeof(df));
memset(head,-1,sizeof(head));
memset(mark,false,sizeof(mark));
}
double dist(int i,int j)
{
double dx=(X[i]-X[j])*(X[i]-X[j])*1.0;
double dy=(Y[i]-Y[j])*(Y[i]-Y[j])*1.0;
return sqrt(dx+dy);
}
void creat(double m)
{
for(int i=0;i<2*n;i++)
{
for(int j=0;j<2*n;j++)
{
if((i>>1)!=(j>>1))
{
if(dist(i,j)<m*2)
{
addedg(i,j^1);
addedg(j,i^1);
}
}
}
}
}
int tarjan(int u)
{
int lowu=df[u]=++clo;
S.push(u);
for(int i=head[u];i+1;i=g[i].nt)
{
int to=g[i].to;
if(!df[to])
{
int lowv=tarjan(to);
lowu=min(lowu,lowv);
}
else if(!bel[to])lowu=min(lowu,df[to]);
}
if(df[u]==lowu)
{
cnt++;
int tmp;
do
{
tmp=S.top(),S.pop();
bel[tmp]=cnt;
}while(tmp!=u);
}
return lowu;
}
bool check( )
{
for(int i=0;i<2*n;i++)
{
if(!df[i])tarjan(i);
}
for(int i=0;i<2*n;i+=2)
{
if(bel[i]==bel[i+1])return false;
}
return true;
}
int main()
{
while(scanf("%d",&n)!=EOF){
rep(i,0,2*n-1)scanf("%d%d",&X[i],&Y[i]);
double l=0;
double r=9999999;
while(r-l>=1e-6)
{
double m=(l+r)*0.5;
init();
creat(m);
if(check( ))l=m;
else r=m;
}
printf("%.2f\n",r);
}
}
2.
Peaceful Commission
解题思路:输出字典序最小的解。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define N 20000
int X[N],Y[N];
struct node
{
int to,nt;
}g[N*20];
int n;
int tot,top;
int s[N];
int head[N],mark[N];
void addedg(int x,int y)
{
g[tot].to=y;
g[tot].nt=head[x];
head[x]=tot++;
}
void init()
{
tot=0,top=0;
memset(head,-1,sizeof(head));
memset(mark,false,sizeof(mark));
}
bool dfs(int u)
{
if(mark[u^1])return false;
if(mark[u]) return true;
mark[u]=true;
s[++top]=u;
for(int i=head[u];i+1;i=g[i].nt)
{
int v=g[i].to;
if(!dfs(v))return false;
}
return true;
}
bool check( )
{
for(int i=0;i<2*n;i+=2)
{
if(!mark[i]&&!mark[i+1])
{
top=0;
if(!dfs(i))
{
while(top)mark[s[top--]]=false;
if(!dfs(i+1)) return false;
}
}
}
return true;
}
int main()
{
int m;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
rep(i,1,m)
{
int x,y;
scanf("%d%d",&x,&y);
x--;
y--;
addedg(x,y^1);
addedg(y,x^1);
}
if(check())
{
for(int i=0;i<2*n;i++)
{
if(mark[i])printf("%d\n",i+1);
}
}else puts("NIE");
}
}
Ikki's Story IV - Panda's Trick
题目大意:给出了一些曲线,要么从圆外连,要么从圆内连,问这些曲线会不会相交。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define pb(x) push_back(x)
#define N 10000
struct node
{
int x,y;
}a[N];
vector<int>G[N];
int cnt,clo;
int df[N],bel[N];
stack<int>S;
void addedg(int x,int v1,int y,int v2)
{
x=x*2+v1;
y=y*2+v2;
G[x^1].pb(y);
G[y^1].pb(x);
}
bool ok(int i,int j)
{
if(a[i].y>a[j].x&&a[i].y<a[j].y&&a[i].x<a[j].x)return true;
if(a[i].x>a[j].x&&a[i].x<a[j].y&&a[i].y>a[j].y)return true;
return false;
}
int dfs(int u)
{
int lowu=df[u]=++clo;
S.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!df[v])
{
int lowv=dfs(v);
lowu=min(lowu,lowv);
}
else if(!bel[v])lowu=min(lowu,df[v]);
}
if(lowu==df[u])
{
cnt++;
int tmp;
do
{
tmp=S.top(),S.pop();
bel[tmp]=cnt;
}while(tmp!=u);
}
return lowu;
}
bool solve(int m)
{
for(int i=0;i<2*m;i++)if(!df[i])dfs(i);
for(int i=0;i<2*m;i+=2)
{
if(bel[i]==bel[i+1])return false;
}
return true;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
rep(i,0,m-1)
{
scanf("%d%d",&a[i].x,&a[i].y);
if(a[i].x>a[i].y)swap(a[i].x,a[i].y);
}
for(int i=0;i<m;i++)
{
for(int j=i+1;j<m;j++)
{
if(ok(i,j))
{
addedg(i,1,j,1);
addedg(i,0,j,0);
}
}
}
if(solve(m))puts("panda is telling the truth...");
else puts("the evil panda is lying again");
}
/*
7 4
1 2
6 3
7 4
5 1
*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define pb(x) push_back(x)
#define N 10000
struct node
{
int x,y;
}a[N];
vector<int>G[N];
int cnt,clo;
int df[N],bel[N];
stack<int>S;
void addedg(int x,int y)
{
G[x].pb(y);
G[y^1].pb(x^1);
}
bool ok(int i,int j)
{
if(a[i].y>a[j].x&&a[i].y<a[j].y&&a[i].x<a[j].x)return true;
if(a[i].x>a[j].x&&a[i].x<a[j].y&&a[i].y>a[j].y)return true;
return false;
}
int dfs(int u)
{
int lowu=df[u]=++clo;
S.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!df[v])
{
int lowv=dfs(v);
lowu=min(lowu,lowv);
}
else if(!bel[v])lowu=min(lowu,df[v]);
}
if(lowu==df[u])
{
cnt++;
int tmp;
do
{
tmp=S.top(),S.pop();
bel[tmp]=cnt;
}while(tmp!=u);
}
return lowu;
}
bool solve(int m)
{
for(int i=0;i<2*m;i++)if(!df[i])dfs(i);
for(int i=0;i<2*m;i+=2)
{
if(bel[i]==bel[i+1])return false;
}
return true;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
rep(i,0,m-1)
{
scanf("%d%d",&a[i].x,&a[i].y);
if(a[i].x>a[i].y)swap(a[i].x,a[i].y);
}
for(int i=0;i<m;i++)
{
for(int j=i+1;j<m;j++)
{
if(ok(i,j))
{
addedg(2*i,2*j+1);
addedg(2*i+1,2*j);
}
}
}
if(solve(m))puts("panda is telling the truth...");
else puts("the evil panda is lying again");
}
/*
7 4
1 2
6 3
7 4
5 1
*/
Map Labeler
要求一些矩形不能相交,判断比较麻烦。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define pb(x) push_back(x)
#define N 2000
struct node
{
int x,y;
}a[N];
vector<int>G[N];
int cnt,clo;
int df[N],bel[N];
stack<int>S;
void addedg(int x,int y)
{
G[x].pb(y);
G[y^1].pb(x^1);
}
void init(int n)
{
cnt=0,clo=0;
memset(df,0,sizeof(df));
memset(bel,0,sizeof(bel));
for(int i=0;i<2*n;i++)G[i].clear();
}
//2*i up 2*i+1 down
void ok(int i,int j,int m)
{
if(abs(a[i].x-a[j].x)<m)
{
if(abs(a[i].y-a[j].y)<m)
{
if(a[i].y==a[j].y) //两者不同即可
{
addedg(i*2,j*2+1);
addedg(i*2+1,j*2);
}
else if(a[i].y>a[j].y) //i必选上,j必选下。
{
G[2*i+1].pb(2*i);
G[2*j].pb(2*j+1);
}
else //i必选下,j必选上
{
G[2*i].pb(2*i+1);
G[2*j+1].pb(2*j);
}
}
else if(abs(a[i].y-a[j].y)<2*m)
{
if(a[i].y>a[j].y)
{
addedg(2*i+1,2*j+1);
}
else addedg(2*i,2*j);
}
}
}
int dfs(int u)
{
int lowu=df[u]=++clo;
S.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!df[v])
{
int lowv=dfs(v);
lowu=min(lowu,lowv);
}
else if(!bel[v])lowu=min(lowu,df[v]);
}
if(lowu==df[u])
{
cnt++;
int tmp;
do
{
tmp=S.top(),S.pop();
bel[tmp]=cnt;
}while(tmp!=u);
}
return lowu;
}
bool solve(int m)
{
for(int i=0;i<2*m;i++)if(!df[i])dfs(i);
for(int i=0;i<2*m;i+=2)
{
if(bel[i]==bel[i+1])return false;
}
return true;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
rep(i,0,n-1)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
int l=0;
int r=50000;
while(l<=r)
{
int m=(l+r)>>1;
init(n);
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
ok(i,j,m);
}
}
if(solve(n))l=m+1;
else r=m-1;
//cout<<l<<" "<<r<<endl;
}
printf("%d\n",r);
}
}
Wedding
有坑见注释。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define pb(x) push_back(x)
#define N 1000
int n,m;
vector<int>G[N];
int mark[N];
int top;
int s[N];
void init()
{
memset(mark,false,sizeof(mark));
top=0;
for(int i=0;i<4*n;i++)G[i].clear();
}
char s1[8],s2[8];
void addedg(int x,int y)
{
G[x].pb(y);
G[y^1].pb(x^1);
}
int get_id(char *p)
{
int len=strlen(p);
int sum=0;
for(int i=0;i<len-1;i++)sum=sum*10+p[i]-'0';
if(p[len-1]=='h')return sum*2+1;
else return sum*2;
}
void input( )
{
int x,y;
G[0].pb(1);
for(int i=1;i<=m;i++)
{
scanf("%s%s",s1,s2);
x=get_id(s1);
y=get_id(s2);
addedg(x,y^1);
}
}
bool dfs(int u)
{
if(mark[u^1])return false;
if(mark[u])return true;
mark[u]=true;
s[++top]=u;
for(int i=0;i<G[u].size();i++)
{
if(!dfs(G[u][i]))return false;
}
return true;
}
bool solve()
{
if(!dfs(1))return false;//因为新娘那一侧可能会有矛盾,2-sat解决的是没有矛盾的一侧
for(int i=2;i<n*2;i++)//因为要保证新娘对面没有矛盾,所以新郎是必选的。
{
if(!mark[2*i]&&!mark[2*i+1])
{
top=0;
if(!dfs(2*i))
{
while(top)mark[s[top--]]=false;
if(!dfs(2*i+1)) return false;
}
}
}
return true;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)break;
init();
input();
if(solve())
{
for(int i=1;i<n;i++)
{
printf("%d",i);
if(mark[i*2])printf("h");
else printf("w");
if(i==n-1)printf("\n");
else printf(" ");
}
}else puts("bad luck");
}
}
Katu Puzzle
给出了一些表达式,求满足条件的值。
逗号写成分号了。。。wa了一下午。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define pb(x) push_back(x)
#define N 2005
int n,m;
struct node
{
int to,nt;
}g[5000005];
int tot;
int head[N];
void addedg(int x,int y)
{
g[tot].to=y;
g[tot].nt=head[x];
head[x]=tot++;
}
void input()
{
int a,b,c;
char s[8];
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%s",&a,&b,&c,s);
if(s[0]=='A')
{
if(c==1)addedg(2*a+1,2*a),addedg(2*b+1,2*b);
else addedg(2*a,2*b+1),addedg(2*b,2*a+1);
}
else if(s[0]=='O')
{
if(c==1)addedg(2*a+1,2*b),addedg(2*b+1,2*a);
else addedg(2*a,2*a+1),addedg(2*b,2*b+1);
}
else if(s[0]=='X')
{
if(c==1)addedg(2*a,2*b+1),addedg(2*b,2*a+1),addedg(2*a+1,2*b),addedg(2*b+1,2*a);
else addedg(2*a,2*b),addedg(2*b+1,2*a+1),addedg(2*a+1,2*b+1),addedg(2*b,2*a);
}
}
}
int df[N],bel[N];
int top,clo,cnt;
int s[N];
int dfs(int u)
{
int lowu=df[u]=++clo;
s[++top]=u;
for(int i=head[u];i+1;i=g[i].nt)
{
int v=g[i].to;
if(!df[v])
{
int lowv=dfs(v);
lowu=min(lowu,lowv);
}
else if(!bel[v]) lowu=min(lowu,df[v]);
}
if(lowu==df[u])
{
cnt++;
int tmp;
do
{
tmp=s[top--];
bel[tmp]=cnt;
}while(tmp!=u);
}
return lowu;
}
bool solve()
{
for(int i=0;i<2*n;i++)if(!df[i])dfs(i);
for(int i=0;i<2*n;i+=2)
{
if(bel[i]==bel[i+1])return false;
}
return true;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
input();
if(solve())puts("YES");
else puts("NO");
}
Eliminate the Conflict
题目大意:两个人石头剪刀布,男孩每局出的已知,女孩每次只能赢或者平局。然后给了一些限制条件,第a局和第b局女孩必须出的一样或者必须不一样。
解题思路:因为男孩的固定之后,女孩每局只有两个选择,可以转化为2sat。然后就是注意建图的时候。
比如第a局和第b局分别是
1 3
2 3
要求第a局和第b局不相等,此时如果我们判断不相等的话就会出错,比如1 2 不相等我们连一条1-2的边,因为要连对称边所以我们还要连一条3-3的边。。。此时就出错了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<map>
#include<vector>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define pb(x) push_back(x)
#define sca(x) scanf("%d",&x)
#define LL long long
#define N 20005
int n,m;
vector<int>G[N];
int a[N];
int b[N][3];
void addedg(int x,int y)
{
G[x].pb(y);
G[y^1].pb(x^1);
}
int mark[N];
int s[N];
int top;
bool dfs(int u)
{
if(mark[u^1])return false;
if(mark[u])return true;
mark[u]=1;
s[++top]=u;
for(int i=0; i<G[u].size(); i++)
{
if(!dfs(G[u][i]))return false;
}
return true;
}
bool solve()
{
memset(mark,false,sizeof(mark));
for(int i=0; i<2*n; i+=2)
{
if(!mark[i]&&!mark[i+1])
{
top=0;
if(!dfs(i))
{
while(top)mark[s[top--]]=false;
if(!dfs(i+1))return false;
}
}
}
return true;
}
int main()
{
int t;
scanf("%d",&t);
int cas=1;
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0; i<n*2; i++)G[i].clear();
rep(i,0,n-1)sca(a[i]);
rep(i,0,n-1)
{
b[i][0]=a[i];
b[i][1]=(a[i]+1)%3;
if(b[i][1]==0)b[i][1]=3;
}
int x,y,z;
rep(i,1,m)
{
sca(x),sca(y),sca(z);
x--,y--;
if(z)
{
for(int j=0; j<2; j++)
{
for(int k=0; k<2; k++)
{
if(b[x][j]==b[y][k])
{
addedg(x*2+j,(y*2+k)^1);
}
}
}
}
else
{
for(int j=0; j<2; j++)
{
for(int k=0; k<2; k++)
{
if(b[x][j]!=b[y][k])
{
addedg(x*2+j,(y*2+k)^1);
}
}
}
}
}
printf("Case #%d: ",cas++);
if(solve())puts("yes");
else puts("no");
}
}
Priest John's Busiest Day
题目大意:n对新人结婚要求结婚的时间段不能相交,输出可行解。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define LL long long
#define N 5005
int a[N];
int b[N*2][2];
struct node
{
int to,nt;
}g[N*N];
int tot;
int head[N];
void addedg(int x,int y)
{
g[tot].to=y;
g[tot].nt=head[x];
head[x]=tot++;
}
bool judge(int x,int y)
{
if(b[y][0]>=b[x][0]&&b[y][0]<b[x][1])return true;
if(b[x][0]>=b[y][0]&&b[x][0]<b[y][1])return true;
return false;
}
void creat(int n)
{
for(int i=0;i<n*2;i++)
{
for(int j=i+1;j<n*2;j++)
{
if((i>>1)!=(j>>1))
{
if(judge(i,j))
{
addedg(i,j^1);
addedg(j,i^1);
}
}
}
}
}
int s[N],top;
int mark[N];
bool dfs(int u)
{
if(mark[u^1])return false;
if(mark[u])return true;
mark[u]=1;
s[++top]=u;
for(int i=head[u];i+1;i=g[i].nt)
{
int to=g[i].to;
if(!dfs(to))return false;
}
return true;
}
bool solve(int n)
{
for(int i=0;i<2*n;i+=2)
{
if(!mark[i]&&!mark[i+1])
{
top=0;
if(!dfs(i))
{
while(top)mark[s[top--]]=false;
if(!dfs(i+1))return false;
}
}
}
return true;
}
int main()
{
int n;
scanf("%d",&n);
memset(head,-1,sizeof(head));
int h1,f1,h2,f2;
int now=0;
for(int i=0;i<n;i++)
{
scanf("%d:%d",&h1,&f1);
scanf("%d:%d",&h2,&f2);
scanf("%d",&a[i]);
b[now][0]=h1*60+f1;
b[now++][1]=h1*60+f1+a[i];
b[now][0]=h2*60+f2-a[i];
b[now++][1]=h2*60+f2;
}
creat(n);
if(!solve(n))puts("NO");
else
{
puts("YES");
for(int i=0;i<2*n;i+=2)
{
if(mark[i])
{
printf("%02d:%02d ",b[i][0]/60,b[i][0]%60);
printf("%02d:%02d\n",(b[i][0]+a[i/2])/60,(b[i][0]+a[i/2])%60);
}
else
{
printf("%02d:%02d ",(b[i+1][1]-a[i/2])/60,(b[i+1][1]-a[i/2])%60);
printf("%02d:%02d\n",(b[i+1][1])/60,(b[i+1][1])%60);
}
}
}
}
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define LL long long
#define N 5005
int a[N];
int b[N*2][2];
struct node
{
int to,nt;
}g[N*N];
int tot;
int head[N];
void addedg(int x,int y)
{
g[tot].to=y;
g[tot].nt=head[x];
head[x]=tot++;
}
bool judge(int x,int y)
{
if(b[y][0]>=b[x][0]&&b[y][0]<b[x][1])return true;
if(b[x][0]>=b[y][0]&&b[x][0]<b[y][1])return true;
return false;
}
void creat(int n)
{
for(int i=0;i<n*2;i++)
{
for(int j=i+1;j<n*2;j++)
{
if((i>>1)!=(j>>1))
{
if(judge(i,j))
{
addedg(i,j^1);
addedg(j,i^1);
}
}
}
}
}
int df[N],clock;
int cnt,top;
int s[N],in[N];
int col[N],op[N];
int ou[N],bel[N];
int dfs(int u)
{
int lowu=df[u]=++clock;
s[++top]=u;
for(int i=head[u];i+1;i=g[i].nt)
{
int v=g[i].to;
if(!df[v])
{
int lowv=dfs(v);
lowu=min(lowu,lowv);
}
else if(!bel[v])lowu=min(lowu,df[v]);
}
if(lowu==df[u])
{
cnt++;
int tmp;
do
{
tmp=s[top--];
bel[tmp]=cnt;
}while(tmp!=u);
}
return lowu;
}
void topsort(int n)
{
queue<int>q;
for(int i=1;i<=n;i++){
if(in[i]==0)q.push(i);
}
int now=0;
while(!q.empty())
{
int u=q.front();
q.pop();
ou[++now]=u;
for(int i=head[u];i+1;i=g[i].nt)
{
int v=g[i].to;
in[v]--;
if(in[v]==0)q.push(v);
}
}
}
void go(int u)
{
col[u]=2;
for(int i=head[u];i+1;i=g[i].nt)
{
if(col[u]==0)go(g[i].to);
}
}
bool solve(int n)
{
for(int i=0;i<2*n;i++){
if(!df[i])dfs(i);
}
for(int i=0;i<2*n;i+=2)
{
if(bel[i]==bel[i+1])return false;
}
tot=0;
memset(head,-1,sizeof(head));
for(int i=0;i<2*n;i++)
{
for(int j=head[i];j+1;j=g[j].nt)
{
int to=g[j].to;
if(bel[i]!=bel[to])
{
addedg(bel[to],bel[i]);
in[bel[i]]++;
}
}
}
topsort(cnt);
for(int i=0;i<2*n;i+=2)
{
op[bel[i]]=bel[i+1];
op[bel[i+1]]=bel[i];
}
for(int i=1;i<=cnt;i++)
{
int u=ou[i];
if(col[u])continue;
col[u]=1;
go(op[u]);
}
return true;
}
int main()
{
int n;
scanf("%d",&n);
memset(head,-1,sizeof(head));
int h1,f1,h2,f2;
int now=0;
for(int i=0;i<n;i++)
{
scanf("%d:%d",&h1,&f1);
scanf("%d:%d",&h2,&f2);
scanf("%d",&a[i]);
b[now][0]=h1*60+f1;
b[now++][1]=h1*60+f1+a[i];
b[now][0]=h2*60+f2-a[i];
b[now++][1]=h2*60+f2;
}
creat(n);
if(!solve(n))puts("NO");
else
{
puts("YES");
for(int i=0;i<2*n;i+=2)
{
if(col[bel[i]]==1)
{
printf("%02d:%02d ",b[i][0]/60,b[i][0]%60);
printf("%02d:%02d\n",(b[i][0]+a[i/2])/60,(b[i][0]+a[i/2])%60);
}
else
{
printf("%02d:%02d ",(b[i+1][1]-a[i/2])/60,(b[i+1][1]-a[i/2])%60);
printf("%02d:%02d\n",(b[i+1][1])/60,(b[i+1][1])%60);
}
}
}
}