题意:
有n个村庄,每个村庄有个发电机,村庄之间有路,如果一个村庄开了发电机,那么和该村庄有边直接相连的就可以获得能量(他自己当然也有),并且一个村庄不能获得太多能量,也就是说在且只在一个发电机的供电范围内,然后每个村庄的发电机有一个能工作的时间区间,让你做一个规划,使得每个村庄每天都有且只有一个能量供应
题解:
这个题目的构图思路比较难想,但一个村庄每次只被覆盖一次是很容易想到可以用dlx算法来实现精确覆盖
然后我们来构造一个矩阵来实现题目要求
行:n*16,我们注意到时间是1<=D<=5,这样我们可以枚举每个村庄的工作时间[0,0],[1,1],[1,2],[1,3],,,,[4,5],[5,5]这样一共有16种情况,这样每一行都代表一个村庄选取一个区间时候的状态
列:n*d+n列,首先一个村庄选取一个区间时,我们就把在这个区间内和这个村庄相连的位置都标上1,n*d代表的是n个村庄n天的状态,然后剩下的n列是用来限制只能选取一个区间的,我们在属于村庄i的16行的第n*d+i列都标上1,这样由于精确覆盖的特性,只会选择其中一个
真的是很神奇的构图,顺便搞了个精确覆盖模板
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define PB push_back
#define MP make_pair
#define ll long long
#define MS(a,b) memset(a,b,sizeof(a))
#define LL (rt<<1)
#define RR (rt<<1|1)
#define lson l,mid,LL
#define rson mid+1,r,RR
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lb(x) (x&(-x))
void In(){freopen("in.in","r",stdin);}
void Out(){freopen("out.out","w",stdout);}
const int N=1e2+10;
const int M=1e6+10;
const int Mbit=1e6+10;
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
const double eps=1e-8;
int ans[N];
bool vis[N][N];
struct DLX
{
const static int maxn=60*20;
const static int maxm=60*10;
const static int X=1e5+10;
int n,m,siz;
int H[maxn],S[maxm];
int U[X],D[X],L[X],R[X],col[X],row[X];
void init(int _n,int _m)
{
n=_n;m=_m;
for(int i=0;i<=m;i++){
S[i]=0;
U[i]=D[i]=i;
L[i]=i-1;
R[i]=i+1;
}
R[m]=0;L[0]=m;
siz=m;
for(int i=1;i<=n;i++)
H[i]=-1;
}
void link(int r,int c)
{
++S[col[++siz]=c];
row[siz]=r;
D[siz]=D[c];
U[D[c]]=siz;
U[siz]=c;
D[c]=siz;
if(H[r]<0)H[r]=L[siz]=R[siz]=siz;
else{
R[siz]=R[H[r]];
L[R[H[r]]]=siz;
L[siz]=H[r];
R[H[r]]=siz;
}
}
void remove(int c)
{
L[R[c]]=L[c];R[L[c]]=R[c];
for(int i=D[c];i!=c;i=D[i])
for(int j=R[i];j!=i;j=R[j]){
U[D[j]]=U[j];
D[U[j]]=D[j];
--S[col[j]];
}
}
void resume(int c)
{
for(int i=U[c];i!=c;i=U[i])
for(int j =L[i];j!=i;j=L[j])
++S[col[U[D[j]]=D[U[j]]=j]];
L[R[c]]=R[L[c]]=c;
}
bool dance(int d)
{
if(R[0]==0)return true;
int c=R[0];
for(int i=R[0];i!=0;i=R[i])
if(S[i]<S[c])
c=i;
remove(c);
for(int i=D[c];i!=c;i=D[i]){
ans[(row[i]-1)/16+1]=(row[i]-1)%16;
for(int j=R[i];j!=i;j=R[j])remove(col[j]);
if(dance(d+1))return true;
for(int j=L[i];j!=i;j=L[j])resume(col[j]);
}
resume(c);
return false;
}
}dlx;
int arr[][2]={{1,1},{1,2},{1,3},{1,4},{1,5},
{2,2},{2,3},{2,4},{2,5},
{3,3},{3,4},{3,5},
{4,4},{4,5},
{5,5},
{0,0}};
vector<int>G[N];
int main()
{
//In();
int d,n,m;
while(~scanf("%d%d%d",&n,&m,&d)){
MS(vis,0);
for(int i=1;i<=n;i++){
G[i].clear();
G[i].PB(i);
}
for(int i=1;i<=m;i++){
int a,b;scanf("%d%d",&a,&b);
if(vis[a][b])continue;
vis[a][b]=vis[b][a]=1;
G[a].PB(b);
G[b].PB(a);
}
dlx.init(n*16,n*d+n);
for(int i=1;i<=n;i++){//第i个点
int s,e;scanf("%d%d",&s,&e);
for(int j=0;j<15;j++){
if(arr[j][0]>=s&&arr[j][1]<=e){//区间[arr[j][0],arr[j][1]]是开着的
for(int k=0;k<G[i].size();k++){
int x=G[i][k];//x是和i相连的点
for(int l=arr[j][0];l<=arr[j][1];l++){
dlx.link((i-1)*16+j+1,(x-1)*d+l);
}
}
dlx.link((i-1)*16+j+1,n*d+i);
}
dlx.link((i-1)*16+16,n*d+i);
}
}
if(dlx.dance(0)){
for(int i=1;i<=n;i++)
printf("%d %d\n",arr[ans[i]][0],arr[ans[i]][1]);
}
else puts("No solution");puts("");
}
return 0;
}