I have worked on a bipartite matching problem, and I obviously got a trouble to solve it.
Let me tell you what the problem is about.
As an input form, it gives me N, M which is the number of people at the work and the number of different kind of jobs in the work.
In the following N lines, it tells us s that tells how many kind of job that ith person can do. In the following s numbers, they will tell us that which jobs can ith person can do. The number of the jobs si will satisfy 1<=si<=M.
Then, if each person can work on only one or less job at a time, how many jobs can be done at most?
This is the problem, and I hope this made sense for you;) I apologize my poor english skill. Returning to the point, this is my code.
#include <stdio.h>
int n, m, dfscheck[1003], check[1003], input[1003][1003], back[1003], tmp, count=0;
void dfs(int num)
{
int i, j;
if(check[num]==0)
{
tmp=-1;
check[num]=1;
return;
}
if(dfscheck[num]==1)
return;
dfscheck[num]=1;
for(j=1; j<=input[back[num]][0]; j++)
{
dfs(input[back[num]][j]);
if(tmp==-1)
{
back[input[back[num]][j]]=back[num];
return;
}
}
}
int main(void)
{
int i, j, flag ,k;
scanf("%d %d", &n, &m);
for(i=1; i<=n; i++)
{
scanf("%d", &input[i][0]);
for(j=1; j<=input[i][0]; j++)
scanf("%d", &input[i][j]);
}
for(i=1; i<=n; i++)
{
flag=0;
for(j=1; j<=input[i][0]; j++)
if(check[input[i][j]]==0)
{
check[input[i][j]]=1;
count++;
flag=1;
back[input[i][j]]=i;
break;
}
if(flag==0)
for(j=1; j<=input[i][0]; j++)
{
for(k=0; k<=1001; k++)
dfscheck[k]=0;
tmp=0;
dfs(input[i][j]);
if(tmp==-1)
{
back[input[i][j]]=i;
count++;
}
}
}
printf("%d", count);
return 0;
}
The name of tmp is really bad to understand code, so... tmp works like a flag in the function dfs. It tells whether it has found a matching.
I got wrong answer, neither runtime error nor time exceed. I have read several different codes that others have written, and I couldn't find which part is wrong in my code.
I have found that my code is distinct from others' in the part that I don't define a array, A[i], showing which job is matched to ith person, exactly opposite to Back array in my code. As far as I understood their codes, the purpose of it is to find out ith person has already been matched before we get into dfs. I don't think this case can be happened. Since no flow has come out of the node of ith person, it is impossible for a flow to go from a node of jobs to the node in max flow.
I wanted to say my thoughts even if it is useless, just in case that it helps you give me some advices. Anyway, let me have your opinions!!!
Thank you so much for your time.
One thing that looks weird is:
if(tmp==-1)
{
back[input[i][j]]=i;
count++;
// I would expect to see "break;" here
}
if you find a way to assign person i to a job you increment the count, and then carry on trying to see if you can find an alternative way to assign the same person. This means that you may end up assigning the same person to multiple jobs!
I recommend inserting a "break;" statement once you have found a job for the person.
Related
So, I have an assignment to do in C++, but I can't figure out how to :/
I have to use backtracking, which is completely alien to me.
The problem:
You are given n number of people with their names and m number of relations(friends) between them. Each relation consists of two names, forming a pair of strings. Everyone has at least n/2 friends. The first person has a book which he lends to one of his friends.
The book has to "travel" through everyone and end up in the hands of the first person.
Write out every possible solution.
The input should contain a number for n followed by a number for m followed by m number of rows each containing a relation.
Something like this:
The input...
3 3
Matt Susy
Matt Alan
Susy Alan
...would result in:
Matt Susy Alan Matt
Matt Alan Susy Matt
and so on for more people.
I have been banging my head against the table because no matter what I do, I can't figure it out :/
As I said, this is a relatively new concept for me and every little help would be appreciated :)
The thing is that this code works, but I can't submit it, because the teacher said that someone already approached this problem using this method, so I have to come up with a different solution for it. (Believe it or not, this has happened too many times already...) The base idea can have some resemblance to this one, but a different approach would be better.
Please forgive the names of the variables, english is not my first language so I wrote it using words from my language :)
#include<iostream>
#include<fstream>
using namespace std;
void input_1D(string nev_1D[])
{
ifstream be("skam0286_L6_9.txt");
int x, i, j, k=1, ok;
string akt;
be>>x>>x;
for(i=0; i<2*x; ++i)
{
be>>akt;
for(j=1, ok=1; j<=k; ++j) if(nev_1D[j]==akt) ok=0;
if(ok) nev_1D[k++]=akt;
}
be.close();
}
void input_2D(int &n, int &m, string nev_2D[][3])
{
int i;
ifstream be("skam0286_L6_9.txt");
be>>n>>m;
for(i=1;i<=m;++i) be>>nev_2D[i][1]>>nev_2D[i][2];
be.close();
}
void output(int n, string eredm[])
{
int i;
for(i=1;i<=n;i++) cout<<eredm[i]<<" ";
cout<<endl;
}
bool helyes(int n, string akt, string eredm[])
{
int i, ok=0;
for(i=1; i<n && !ok; ++i)
if(eredm[i]==akt) ok=1;
return ok;
}
bool barat(int m, string nev_2D[][3], string n1, string n2)
{
int i, ok=0;
for(i=1;i<=m && !ok; ++i)
if((n1==nev_2D[i][1] && n2==nev_2D[i][2])||(n1==nev_2D[i][2] && n2==nev_2D[i][1]))
ok=1;
return ok;
}
void bt(int n, int m, string nev_2D[][3], string nev_1D[], string eredm[], int ind)
{
if(ind==n+1){
if(barat(m, nev_2D, eredm[1], eredm[ind-1])){
eredm[ind]=eredm[1];
output(ind, eredm);
}
}
else{
int i;
for(i=1; i<=n; ++i)
if(!helyes(ind, nev_1D[i], eredm) && barat(m, nev_2D, eredm[ind-1], nev_1D[i])){
eredm[ind]=nev_1D[i];
bt(n, m, nev_2D, nev_1D, eredm, ind+1);
}
}
}
int main()
{
int n, m;
string nev_2D[100][3], nev_1D[100], eredm[100];
eredm[1]="Matt";
input_2D(n,m,nev_2D);
input_1D(nev_1D);
bt(n, m, nev_2D, nev_1D, eredm, 2);
return 0;
}
I should resolve 16-Queens Problem in 1 second.
I used backtracking algorithm like below.
This code is enough to resolve N-Queens Problem in 1 second when the N is smaller than 13.
But it takes long time if N is bigger than 13.
How can I improve it?
#include <stdio.h>
#include <stdlib.h>
int n;
int arr[100]={0,};
int solution_count = 0;
int check(int i)
{
int k=1, ret=1;
while (k < i && ret == 1) {
if (arr[i] == arr[k] ||
abs(arr[i]-arr[k]) == abs(i-k))
ret = 0;
k++;
}
return ret;
}
void backtrack(int i)
{
if(check(i)) {
if(i == n) {
solution_count++;
} else {
for(int j=1; j<=n; j++) {
arr[i+1] = j;
backtrack(i+1);
}
}
}
}
int main()
{
scanf("%d", &n);
backtrack(0);
printf("%d", solution_count);
}
Your algorithm is almost fine. A small change will probably give you enough time improvement to produce a solution much faster. In addition, there is a data structure change that should let you reduce the time even further.
First, tweak the algorithm a little: rather than waiting for the check all the way till you place all N queens, check early: every time you are about to place a new queen, check if another queen is occupying the same column or the same diagonal before making the arr[i+1] = j; assignment. This will save you a lot of CPU cycles.
Now you need to speed up checking of the next queen. In order to do that you have to change your data structure so that you could do all your checks without any loops. Here is how to do it:
You have N rows
You have N columns
You have 2N-1 ascending diagonals
You have 2N-1 descending diagonals
Since no two queens can take the same spot in any of the four "dimensions" above, you need an array of boolean values for the last three things; the rows are guaranteed to be different, because the i parameter of backtrack, which represents the row, is guaranteed to be different.
With N up to 16, 2N-1 goes up to 31, so you can use uint32_t for your bit arrays. Now you can check if a column c is taken by applying bitwise and & to the columns bit mask and 1 << c. Same goes for the diagonal bit masks.
Note: Doing a 16 Queen problem in under a second would be rather tricky. A very highly optimized program does it in 23 seconds on an 800 MHz PC. A 3.2 GHz should give you a speed-up of about 4 times, but it would be about 8 seconds to get a solution.
I would change while (k < i && ret == 1) { to while (k < i) {
and instead of ret = 0; do return 0;.
(this will save a check every iteration. It might be that your compiler does this anyway, or some other performance trick, but this might help a bit).
Among n persons,a "celebrity" is defined as someone
who is known by everyone but does not know anyone. The
problem is to identify the celebrity, if one exists, by asking the
question only of the form, "Excuse me, do you know the person
over there?" (The assumption is that all the answers are correct,
and even that celebrity will also answer.)
The goal is to minimize the number of questions.
Is there a solution of the order less than the obvious O(n^2) here?
Using the analysis of the celebrity problem here
Brute-force solution. The graph has at most n(n-1) edges, and we can compute it by asking a question for each potential edge. At this
point, we can check whether a vertex is a sink by computing its
indegree and its outdegree. This brute-force solution asks n(n-1)
questions. Next we show how to to do this with at most 3(n-1)
questions and linear place.
An elegant solution. Our algorithm consists of two phases: in the elimination phase, we eliminate all but one person from being the
celebrity; in the verification phase we check whether this one
remaining person is indeed a celebrity. The elimination phase
maintains a list of possible celebrities. Initially it contains all n
people. In each iteration, we delete one person from the list. We
exploit the following key observation: if person 1 knows person 2,
then person 1 is not a celebrity; if person 1 does not know person 2,
then person 2 is not a celebrity. Thus, by asking person 1 if he knows
person 2, we can eliminate either person 1 or person 2 from the list
of possible celebrities. We can use this idea repeatedly to eliminate
all people but one, say person p. We now verify by brute force
whether p is a celebrity: for every other person i , we ask person p
whether he knows person i , and we ask persons i whether they know
person p . If person p always answers no, and the other people always
answer yes, the we declare person p as the celebrity. Otherwise, we
conclude there is no celebrity in this group.
Divide all the people in pairs.
For every pair (A, B), ask A if he knows B.
if the answer is yes, A can not be the celebrity, discard him.
if the answer is no, B can not be the celebrity, discard him.
Now, only half the people remains.
Repeat from 1 until just one person remains.
Cost O(N).
Here is O(N) time algorithm
Push all the elements into stack.
Remove top two elements(say A and B), and keep A if B knows A and A does not know B.
Remove both A,B is both know each other or both does not know each other
This question can be solved using graphs (indegree and outdegree concept) in O(N^2) Time complexity.
We can also solve this question in O(N) time and O(1) space using a simple two-pointer concept.
We are going to compare two persons at a time one from beginning and other from the end and we will remove that person from consideration which cannot be a celebrity. For example, if there are two persons X and Y and X can identify person Y then surely X cannot be a celebrity as it knows a person inside this party. Another case would be when X does not know Y and in this case, Y cannot be a celebrity as there is at least one person who does not know him/her inside a party. Using this intuition two-pointer concept can be applied to find the celebrity inside this party.
I found a good explanatory video on Youtube by algods.
You can refer to this video for a better explanation.
Video Link:
https://youtu.be/aENYremq77I
Here is my solution.
#include<iostream>
using namespace std;
int main(){
int n;
//number of celebrities
cin>>n;
int a[n][n];
for(int i = 0;i < n;i++){
for(int j = 0;j < n;j++){
cin>>a[i][j];
}
}
int count = 0;
for(int i = 0;i < n;i++){
int pos = 0;
for(int j = 0;j < n;j++){
if(a[i][j] == 0){
count = count + 1;
}
else{
count = 0;
break;
}
}
if(count == n){
pos = i;
cout<<pos;
break;
}
}
return 0;
}
This is how I did it :)
Question - A celebrity is defined someone whom everyone else knows of, but do not know anyone. Given N people (indexed 0...(N-1)), and a function knowsOf defined
as follows: knowsOf(int person0, int person1) = true if person 0 knows person 1, and false otherwise
Find out the celebrity in the N given people if there is any.
// return -1 if there is no celeb otherwise return person index/number.
public int celeb(int n) {
int probaleCeleb = 0;
for(int i =1 ; i < n; i++) {
if(knowsOf(probaleCeleb , i)) { // true /false
probaleCeleb = i;
}
}
for(int i =0 ; i < n; i++) {
if( i != probaleCeleb &&
(!knowsOf( i , probaleCeleb) || (knowsOf( probaleCeleb , i)) ) {
probaleCeleb = -1;
break;
}
}
return probaleCeleb;
}
}
public class Solution {
public int findCelebrity(int n) {
if (n <= 1) {
return -1;
}
int left = 0;
int right = n - 1;
// First find the right candidate known by everyone, but doesn't know anyone.
while (left < right) {
if (knows(left, right)) {
left++;
} else {
right--;
}
}
// Validate if the candidate knows none and everyone knows him.
int candidate = right;
for (int i = 0; i < n; i++) {
if (i != candidate && (!knows(i, candidate) || knows(candidate, i))) {
return -1;
}
}
return candidate;
}
}
int findCelebrity(int n) {
int i=0;
for(int j=1;j<n;j++){
if(knows(i,j)){
i=j;
}
}
for(int j=0;j<n;j++){
if(j!=i && (knows(i,j)|| !knows(j,i))){
return -1;
}
}
return i;
}
Please tell me why this code is giving garbage values
Compiles well, implemented this based on the Cormen algorithm for mergesorting
Basically taking given numbers in a dynamic array. two void functions are taken.One is to merge the two sub arrays via merge sort and the other to recursively split the array to sub arrays
#include<iostream>
using namespace std;
void merge(int *A,int p, int q, int r)// a function to merge two //sub arrays
{
int n1= q-p+1;
int n2=r-q;
int L[n1];
int R[n2];
for (int i=0;i<n1;i++)
{
L[i]=A[p+i];
}
int m=1;
for(int j=0; j<n2 ;j++)
{
R[j]=A[q+m];
m=m+1;
}
int i=0;
int j=0;
for(int k=0;k<r;k++)
{
if (L[i]<=R[j])
{
A[k]=L[i];
i=i+1;
}
else
{
A[k]=R[j];
j=j+1;
}
}
}
void mergesort(int *A,int p,int r)// dividng the sequence to sub arrays
{
if (p<r)
{
int q;
q=(p+r)/2;
mergesort(A,p,q);
mergesort(A,(q+1),r);
merge(A,p,q,r);
}
}
int main()
{
int n;
cout<<"Enter the number of numbers to be sorted by merge sort"<<endl;
cin>>n;
int* a=NULL;
a=new int[n];
int temp;
cout<<"Enter the numbers"<<endl;
for(int i=0;i<n;i++)
{
cin>>temp;
*(a+i)=temp;// inputting the given numbers into a dynamic array
}
cout<<"The given numbers are:"<<endl;
for(int j=0;j<n;j++)
cout<<*(a+j)<<" ";
mergesort(a,0,n-1);
cout<<"The merged sorted numbers are:"<<endl;
for(int s=0;s<n;s++)
cout<<*(a+s)<<" ";
delete [] a;
system("pause");
return 0;
}
You are getting your intervals wrong pretty much everywhere in your code. For example:
Based on your usage in main, mergesort is supposed to sort the sublist of indices [0,n-1].
With this meaning, your recursion in mergesort says in order to sort the indices [p,r-1], you should first sort [p,q-1] then sort [q+1,r-1]: you completely ignore index q.
Similarly, merge is confused: once you fix the typo when coping into L (A[i] should be A[p+i]), it takes [p,q] as one list, and [q,r] as the other list: note you copy entry q twice, and you also copy r when you probably shouldn't be.
To fix your code, you need to straighten out exactly what intervals everything is supposed to be working on. This isn't a hard problem, you just have to bring yourself to write down explicitly exactly what all of your functions and loops and stuff are supposed to be doing.
The typical convention these days is half-open intervals: you should generally think of taking indices [p,q) from a list. ([p,q) is the same as [p,q-1]) Here are several examples of why this is preferred:
The number of entries of [p,r) is simply r-p
A for loop iterating through [p,r) is the usual for(i=p; i<r; ++i) (not <=)
Splitting the interval [p,r) into parts gives you intervals [p,q) and [q,r) -- there is no worry about remembering to add 1 in places.
e.g. merge would normally be designed to take the first list comes from indices [p,q) and the second list from indices [q,r).
I was recently told to improve a for loop is convenient to use decremental for loop instead of incremental loop, like
For(int i=0; i<Limit;i++)
{
//code
}
For(int i=Limit-1; i >=0; i--)
{
//code
}
I am not seeing why some people would recommend using this, their argument was
"using incremental for loops increases the number of validations inside the loop. when using decremental loops validations and processing time are reduced"
Often times, you will see something like this:
for(int i = 0; i < list.length(); i++) {
}
But often you could do instead
for(int i = list.length(); i >= 0; i--) {
}
That way, list.length() is called once.
Of course, this is also a possiblity:
int length = list.length();
for(int i = 0; i < length; i++) {
}
But the first way was shorter.
Rarely do I ever think of fixing a real performance problem with such a trivial and (usually) inconsequential fix. And if for some reason .length() is really eating CPU time, I prefer the last way.