A.免费道路roads
题意:给定n个点m条边的图,边有黑白颜色,求是否有一个生成树满足恰好有K条黑边,并输出方案。
题解:先加白边,求出必须加的黑边,然后加黑边到K条,剩下的用白边填充。
顺便说说,边权只有01的图,生成树的权值和可以取到任意的介于[MST,MBT]的任意值,其中MST表示最小生成树,MBT最大。
我们可以发现MST和MBT的区别在与其中一些点,这些点与生成树联通的边可以选择0或者1,所以你可以把一些点的边替换,每次权值变化1,所以可以取到任意的权值.
#include#include #include #define MN 20000 #define MM 100000 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } struct edge{int from,to;}e[MM+5],e2[MM+5]; int n,m,K,s[MN+5],cnt1=0,cnt2=0,q[MN+5],qx[MN+5],top,top2; int getfa(int x){return !s[x]?x:s[x]=getfa(s[x]);} int kruscal(edge*E,int num,int lim=MM) { top=0; for(int i=1;i<=num&&top ) { int x=getfa(E[i].from),y=getfa(E[i].to); if(x!=y) s[x]=y,q[++top]=i; } return top; } int main() { n=read();m=read();K=read(); for(int i=1;i<=m;i++) { int u=read(),v=read(),k=read(); if(!k) e[++cnt1]=(edge){u,v}; else e2[++cnt2]=(edge){u,v}; } int num1=kruscal(e2,cnt2),num2=kruscal(e,cnt1); if(num2>K||cnt1 1) return 0*puts("no solution"); memset(s,0,sizeof(s));top2=top; for(int i=1;i<=top;i++) qx[i]=q[i],s[getfa(e[q[i]].from)]=getfa(e[q[i]].to); if(kruscal(e,cnt1,K-num2) return 0*puts("no solution"); for(int i=1;i<=top2;i++)printf("%d %d %d\n",e[qx[i]].from,e[qx[i]].to,0); for(int i=1;i<=top;i++) printf("%d %d %d\n",e[q[i]].from,e[q[i]].to,0); kruscal(e2,cnt2); for(int i=1;i<=top;i++) printf("%d %d %d\n",e2[q[i]].from,e2[q[i]].to,1); return 0; }
B.DNA
给定一个长度为m的由ACGTN组成的字符串,定义大小关系A $m\leqslant 50000 R\leqslant 10^{12} k\leqslant 10$ 题解:用f[i][j][k]表示第i到n位第i位是k,这部分分了j段的个数,这个容易转移,然后我们就一步步走呗。复杂度 O(16mk) #include