#21 T3:mst
题意:给n(1~100000)个点,m条边(n-1<=m<=min(n*n-1,1e5),保证能够形成一棵树
求解:对于每一条边,求出每一条边是否在所有最小生成树上(any),或者至少在一颗最小生成树上(at least one),或者不在任何一棵树上(none)
思路:将权值排序,对所有权值相同的边一起操作。如果两条边在同一个连通分量,该边为none。
构造一个新图G1,将所有边对应的连通分量连边,然后求桥,所有的桥即为any,剩下的所有边为at least one
直到目前连边的数量超过n-1次,退出循环。 下面贴代码:
#include<stdio.h>
#include<algorithm>
#define N 100111
struct edge{ //原边
int a, b, v, id;
bool operator <(const edge& x)const{return v<x.v;}
}e[N];
struct edge2{ //新图的边
int d, to, id;
}E[2*N];
int len, fa[N], pd[N], fi[N], vis[N], ans[N];
int first[N], low[N], dfn[N], num, Id; //建新图的数组
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline void add(int a, int b, int c){
E[++num].d=b;E[num].to=first[a];E[num].id=c;first[a]=num;
E[++num].d=a;E[num].to=first[b];E[num].id=c;first[b]=num;
}
void dfs(int u, int id){
vis[u]=1;
low[u]=dfn[u]=++Id;
for(int i=first[u];i;i=E[i].to){
int d=E[i].d;
if(!vis[d]){
dfs(d,E[i].id);
if(dfn[u]<low[d]) ans[E[i].id]=1;
if(low[d]<low[u]) low[u]=low[d];
} else if(vis[d]&&id!=E[i].id&&dfn[d]<low[u]) low[u]=dfn[d];
} vis[u]=0;
}
int tarjan(int l, int r){
len=num=Id=0; //记得每次清0
for(int i=l;i<=r;i++){
int f1=find(e[i].a), f2=find(e[i].b);
if(f1==f2){
ans[e[i].id]=-1;
continue;
} if(!pd[f1]) fi[++len]=f1,pd[f1]=1;
if(!pd[f2]) fi[++len]=f2,pd[f2]=1;
add(f1,f2,e[i].id);
} for(int i=1;i<=len;i++) if(!dfn[fi[i]]) dfs(fi[i],0);
for(int i=1;i<=len;i++) dfn[fi[i]]=low[fi[i]]=0;
int cnt=0; //下面记得把之前用过的连边清0,否则会WA
for(int i=l;i<=r;i++){
int f1=find(e[i].a), f2=find(e[i].b);
pd[f1]=pd[f2]=first[f1]=first[f2]=0;
if(f1!=f2) fa[f2]=f1,cnt++;
} return cnt;
}
int main(){
freopen("mst.in","r",stdin);
freopen("mst.out","w",stdout);
int n, m, l=1, r=1;
scanf("%d%d", &n, &m);
for(int i=1;i<=m;i++){
scanf("%d %d %d", &e[i].a, &e[i].b, &e[i].v);
e[i].id=i;
} std::sort(e+1,e+m+1); e[m+1].v=-1;
for(int i=1;i<=n;i++) fa[i]=i;
int cnt=0;
while(l<=m){
while(e[r+1].v==e[r].v&&r<=m) r++;
tarjan(l,r);
if(cnt>=n) break;
l=r=r+1;
} for(int i=1;i<=m;i++)
if(ans[i]==-1) puts("none");
else if(ans[i]) puts("any");
else puts("at least one");
return 0;
}
#41 T2 part
题意:给你n个人,把所有人分成两队,对任意甲同学,必须使得与甲同学同队的人都愿意和甲同学同队,无解输出no solution
思路:二分图染色 将所有不能同队的同学连一条边,无法形成二分图则无解
有解时,对于每一个连通块,得到块内0和1的数量,然后进行背包求解
#include<cstdio>
#include<queue>
#define N 2011
using namespace std;
inline int read(){
int t=getchar(), p=0;
while(t<'0'||t>'9') t=getchar();
while(t>='0'&&t<='9') p=p*10+t-48, t=getchar();
return p;
}
struct edge{
int d, to;
}e[N*N];
int num=0, first[N];
inline void add(int a, int b){
e[++num].d=b;e[num].to=first[a];first[a]=num;
}
int n, cnt=0, co[N], g[N][N], dp[N], c1[N][2];
queue<int>s;
int bfs(int u){
while(!s.empty()) s.pop();
s.push(u);c1[cnt][1]++;
while(!s.empty()){
int x=s.front();s.pop();
for(int i=first[x];i!=-1;i=e[i].to){
int d=e[i].d;
if(co[d]==-1){
co[d]=!co[x];
s.push(d);
c1[cnt][co[d]]++;
} else if(co[d]==co[x]) return 1;
}
} return 0;
}
int pre(){
for(int i=1;i<=n;i++)
if(co[i]==-1) {
cnt++;co[i]=1;
if(bfs(i)) return 1;
} return 0;
}
int main(){
freopen("part.in","r",stdin);
freopen("part.out","w",stdout);
int x;n=read();
for(int i=1;i<=n;i++){
while(1){
x=read();
if(!x) break;
g[i][x]=1;
} first[i]=-1,co[i]=-1;
} for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) if(g[i][j]==0&&i!=j) add(i,j),add(j,i);
if(pre()){
puts("No solution");
return 0;
} dp[0]=1;
int m=n/2;
for(int i=1;i<=cnt;i++)
for(int j=m;j>0;j--){
if(j>=c1[i][1]) dp[j]|=dp[j-c1[i][1]];
if(j>=c1[i][0]) dp[j]|=dp[j-c1[i][0]];
} for(int j=m;j>0;j--){
if(dp[j]){
printf("%d %d\n", j, n-j);
return 0;
}
} return 0;
}
#41 T3 kobe
给一个图,求起点s走k次到终点t的最小距离
思路:快速幂
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 211
#define inf 1047480000
using namespace std;
inline int read(){
int t=getchar(), p=0, f=1;
while(t<'0'||t>'9'){
if(t=='-') f=-1;
t=getchar();
}
while(t>='0'&&t<='9') p=p*10+t-48, t=getchar();
return p*f;
}
int n, S, T, K;
void min(int& x, int y){
if(x>y) x=y;
}
struct Mat{
int g[N][N];
Mat operator *(Mat& b){
Mat c;int i, j, k;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
for(c.g[i][j]=inf,k=1;k<=n;k++) min(c.g[i][j],g[i][k]+b.g[k][j]);
return c;
}
}f;
int main(){
freopen("kobe.in","r",stdin);
freopen("kobe.out","w",stdout);
n=read(), S=read(), T=read(), K=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
f.g[i][j]=read();
if(f.g[i][j]==-1) f.g[i][j]=inf;
} Mat ans=f; K--;
while(K){
if(K&1) ans=ans*f;
K>>=1; f=f*f;
} if(ans.g[S][T]!=inf) printf("%d\n", ans.g[S][T]);
else puts("-1");
// printf("%d\n", inf);
return 0;
}