Description
Input
Output
Sample Input
1 2
3 2
4 5
Sample Output
HINT
[Data range]
For 30% of the data, ensure N < = 1000
For 100% of the data, ensure N < = 1000000
Problem solving Here!
When I saw the data range of n<=100w, I was instantly stunned. . .
Then I read the question several times
For attributes x,y of item i, connect a directed edge from x and y to i , respectively. Take the damage value as the left point, the equipment number as the right point, and find the maximum match.
So quickly fired Hungary, but TLE. Why?
Because the vis array must be cleared to false every time, the vis array is at least 1w, and of course TLE. . .
How to do it?
We can convert the vis array from bool to int, initially clear it to 0, and then open a time, +1 each time.
Then every time you judge vis(int)==time, you can achieve the effect of vis(bool)==true.
Prove? Isn't it just to judge whether vis has been modified every time. . .
Note:
1. Use the forward star to save the image .
2. If the current damage value cannot be matched, jump out directly.
Attached code:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define MAXN 1000010 using namespace std; int n,c=1,id=0,f[MAXN],head[MAXN],vis[MAXN]; struct node{ int next,to; }a[MAXN<<1]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline void add(int x,int y){ a[c].to=y;a[c].next=head[x];head[x]=c++; } bool find(int x){ for(int i=head[x];i;i=a[i].next){ int v=a[i].to; if(vis[v]!=id){ force[v]=id; if(f[v]==-1||find(f[v])){ f[v]=x; return true; } } } return false; } void work(){ int ans=0; for(int i=1;i<=10000;i++){ id++; if(find(i))ans++; else break; } printf("%d\n",ans); } void init(){ int x,y; n=read(); memset(f,-1,sizeof(f)); for(int i=1;i<=n;i++){ x=read();y=read(); add(x,i);add(y,i); } } int main(){ init(); work(); return 0; }
However, there are more powerful algorithms for this problem - and check the set!
The first time I saw dalao's solution to a combined set of questions on the Internet, I was stunned. . .
Consider a weapon with properties a and b as an undirected edge between points a and b.
For a connected block, if there is no ring (that is, a tree), then any p-1 points in it must be satisfied.
For a connected block, if it contains a ring, then all p points must be satisfied.
Then a vis can be used to maintain this property when merging and checking sets.
Think of weights as points and weapons as edges.
If the edge added each time is to merge two connected blocks, merge the connected blocks with smaller weights to the connected blocks with larger weights, and then give vis=true with small weights
If not, put vis=true on the vertices of the connected block.
This ensures that if a block of size N is connected:
1. Consists of N-1 edges, vis=false for the largest point, and true for others.
2. Consists of ≥N edges, and vis=true for all points.
Then at the end only one scan of vis can get the answer.
Attached code:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 1000010 using namespace std; int n, fa [MAXN]; bool vis[MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} inline void uniun(int x,int y){ x=find(x);y=find(y); if(x==y)vis[x]=true; else{ if(x<y)swap(x,y); if (vis [y]) vis [x] = true; else vis [y] = true; fa [y] = x; } } int main(){ int x,y; n=read(); for(int i=1;i<=n+1;i++){fa[i]=i;vis[i]=false;} for(int i=1;i<=n;i++){ x=read();y=read(); uniun(x,y); } for(int i=1;i<=10001;i++)if(!vis[i]){printf("%d\n",i-1);break;} return 0; }