@ysner
2018-10-30T11:57:04.000000Z
字数 5211
阅读 2209
最短路 贪心
林先森发现很多同学突然学会了毒瘤算法,他决定调查一下这是怎么一回事。
一共有个人,林先森知道开始时只有号会毒瘤算法。林先森了解到很多人一起吃过
午餐;具体地,有条信息,其中第条信息描述和在区间中的某一天一起吃
了午餐。若此时或中的一个人会毒瘤算法,那么两个人都能学会毒瘤算法。特别地,若
一个人在某天和多个人一起吃午餐,那么他在学会毒瘤算法的同时会立即教给别人(同一天的
午餐均视作同时发生)。
林先森知道最后学会了毒瘤算法的同学以及没有学会毒瘤算法的同学,以及一些不确定是
否学会了毒瘤算法的同学。林先森想知道大家具体在哪一天共用了午餐,或者告诉林先森这样
的结果是不可能出现的。
做难题从部分分开始。
显然,如果有这条性质,可以推个贪心结论:每个人尽早学会毒瘤算法肯定是最优的。
所以可以设表示第个人最早学会毒瘤算法的时间。
然后发现转移等价于最短路。
那么拿跑一跑就行。
#include<iostream>#include<cmath>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<queue>#define ll long long#define re register#define il inline#define pi pair<int,int>#define mk make_pair#define fi first#define se second#define fp(i,a,b) for(re int i=a;i<=b;++i)#define fq(i,a,b) for(re int i=a;i>=b;--i)using namespace std;const int N=20,M=2e5+100;int n,m,cho[N],tar[M],top[N],mx,tag=1;struct dat{int u,v,L,R;}a[M],sta[10][N];bool vis[M];int h[M],cnt,dis[M];struct Edge{int to,nxt,mn,mx;}e[M<<1];il void add(re int u,re int v,re int mn,re int mx){e[++cnt]=(Edge){v,h[u],mn,mx};h[u]=cnt;e[++cnt]=(Edge){u,h[v],mn,mx};h[v]=cnt;}il ll gi(){re ll x=0,t=1;re char ch=getchar();while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();if(ch=='-') t=-1,ch=getchar();while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();return x*t;}il void out(){fp(i,1,m) printf("%d\n",cho[i]);exit(0);}il void check(){fp(i,1,n) vis[i]=0;vis[1]=1;fp(i,1,mx){fp(j,1,top[i]) if(vis[sta[i][j].u]||vis[sta[i][j].v]) vis[sta[i][j].u]=vis[sta[i][j].v]=1;fp(j,1,top[i]) if(vis[sta[i][j].u]||vis[sta[i][j].v]) vis[sta[i][j].u]=vis[sta[i][j].v]=1;}re int tag=1;fp(i,1,n) if((tar[i]==1&&!vis[i])||(tar[i]==-1&&vis[i])) {tag=0;break;}if(tag) out();}il void dfs(re int x){if(x>m) {check();return;}fp(i,a[x].L,a[x].R){mx=max(mx,a[x].R);cho[x]=i;sta[i][++top[i]]=a[x];dfs(x+1);--top[i];}}il int min(re int x,re int y){return x<y?x:y;}il int max(re int x,re int y){return x>y?x:y;}il void Dijstra(){priority_queue<pi,vector<pi>,greater<pi> >Q;while(!Q.empty()) Q.pop();fp(i,1,n) vis[i]=0,dis[i]=1e9+7;dis[1]=0;Q.push(mk(0,1));while(!Q.empty()){re int u=Q.top().se;Q.pop();vis[u]=1;for(re int i=h[u];i+1;i=e[i].nxt){re int v=e[i].to,mx=e[i].mx,mn=e[i].mn;if(dis[v]>max(mn,dis[u])&&dis[u]<=mx){dis[v]=max(mn,dis[u]);Q.push(mk(dis[v],v));}}while(!Q.empty()&&vis[Q.top().se]) Q.pop();}}il void solve(){memset(h,-1,sizeof(h));fp(i,1,m) add(a[i].u,a[i].v,a[i].L,a[i].R);Dijstra();fp(i,1,n) if(tar[i]==1&&dis[i]>1e9) {puts("Impossible");exit(0);}fp(i,1,m) printf("%d\n",dis[a[i].u]>a[i].R?a[i].L:max(a[i].L,dis[a[i].u]));exit(0);}int main(){n=gi();m=gi();fp(i,1,m){a[i].u=gi(),a[i].v=gi(),a[i].L=gi(),a[i].R=gi();}fp(i,1,n) tar[i]=gi(),tag&=(tar[i]>=0);if(n>12&&tag) solve();//for ex35ptsdfs(1);//for 10ptsputs("Impossible");return 0;}
直接想是有难度的。
但有作为铺垫就比较好想了。
如果有确定没学会的人,相当于给他周围的人(与他吃饭的人)的的下限。
因为他们吃饭的时间一定在,然后就必须大于,即下限为。
(接下来这点自己没想到)
然后这个下限的影响是可以扩散的。
设一个人为,和他吃饭的某人为。
如果,就说明不能给传授算法,那么他们吃饭时不应该会算法。
为保证最小,吃饭时间一定为,则。
这个过程可以用最短路维护。
在此基础上,贪心显然仍成立。
那么接着最短路转移,过程中保证即可。
#include<iostream>#include<cmath>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<queue>#define ll long long#define re register#define il inline#define pi pair<int,int>#define mk make_pair#define fi first#define se second#define fp(i,a,b) for(re int i=a;i<=b;++i)#define fq(i,a,b) for(re int i=a;i>=b;--i)using namespace std;const int M=2e5+100;int n,m,tar[M],lim[M];struct dat{int u,v,L,R;}a[M];bool vis[M];int h[M],cnt,dis[M];struct Edge{int to,nxt,mn,mx;}e[M<<1];il void add(re int u,re int v,re int mn,re int mx){e[++cnt]=(Edge){v,h[u],mn,mx};h[u]=cnt;e[++cnt]=(Edge){u,h[v],mn,mx};h[v]=cnt;}il ll gi(){re ll x=0,t=1;re char ch=getchar();while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();if(ch=='-') t=-1,ch=getchar();while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();return x*t;}il int min(re int x,re int y){return x<y?x:y;}il int max(re int x,re int y){return x>y?x:y;}il void Dijstra(){priority_queue<pi,vector<pi>,greater<pi> >Q;while(!Q.empty()) Q.pop();fp(i,1,n) vis[i]=0,dis[i]=1e9+7;dis[1]=0;Q.push(mk(0,1));while(!Q.empty()){re int u=Q.top().se;Q.pop();vis[u]=1;for(re int i=h[u];i+1;i=e[i].nxt){re int v=e[i].to,mx=e[i].mx,mn=e[i].mn,g=max(max(lim[v],mn),dis[u]);if(dis[v]>g&&g<=mx){dis[v]=g;Q.push(mk(dis[v],v));}}while(!Q.empty()&&vis[Q.top().se]) Q.pop();}}il void Pre_SPFA(){queue<int>Q;while(!Q.empty()) Q.pop();fp(i,1,n){tar[i]=gi();if(tar[i]==-1) lim[i]=1e9+7,vis[i]=1,Q.push(i);else vis[i]=0;}while(!Q.empty()){re int u=Q.front();Q.pop();for(re int i=h[u];i+1;i=e[i].nxt){re int v=e[i].to,mn=e[i].mn,mx=e[i].mx;if(lim[u]>mx)if(lim[v]<mn+1){lim[v]=mn+1;if(!vis[v]) vis[v]=1,Q.push(v);}}vis[u]=0;}}int main(){freopen("lunch.in","r",stdin);freopen("lunch.out","w",stdout);memset(h,-1,sizeof(h));n=gi();m=gi();fp(i,1,m){a[i].u=gi(),a[i].v=gi(),a[i].L=gi(),a[i].R=gi();add(a[i].u,a[i].v,a[i].L,a[i].R);}Pre_SPFA();Dijstra();fp(i,1,n)if(tar[i]==1&&dis[i]>1e9) {puts("Impossible");exit(0);}fp(i,1,m){if(tar[a[i].u]==-1)if(dis[a[i].v]<=a[i].L) {puts("Impossible");exit(0);}if(tar[a[i].v]==-1)if(dis[a[i].u]<=a[i].L) {puts("Impossible");exit(0);}}fp(i,1,m){re int u=a[i].u,v=a[i].v;if(tar[u]==-1||tar[v]==-1) printf("%d\n",a[i].L);else printf("%d\n",max(dis[u],dis[v])>a[i].R?a[i].L:max(a[i].L,max(dis[u],dis[v])));}fclose(stdin);fclose(stdout);return 0;}
