#include #include // Test, zda úsečky AB a BC svírají správný úhel pro horní část obalu. #define OK_FOR_TOP(A, B, C) ((B.x - A.x)*(C.y - B.y) <= (B.y - A.y)*(C.x - B.x)) // Test, zda úsečky AB a BC svírají správný úhel pro spodní část obalu. #define OK_FOR_BOTTOM(A, B, C) ((B.x - A.x)*(C.y - B.y) >= (B.y - A.y)*(C.x - B.x)) struct spoint { // Struktura zapouzdřující souřadnice jednoho kůlu. int x, y; }; struct spoint *points; // Pole všech kůlů. int pointsCount = 0; // Počet všech kůlů. /* Načte data ze vstupního souboru do globálních proměnných. */ void load(void) { FILE *fp = fopen("kuly.in", "r"); if (!fp) return; fscanf(fp, "%d\n", &pointsCount); points = malloc(pointsCount * sizeof(struct spoint)); for(int i = 0; i < pointsCount; i++) fscanf(fp, "%d %d\n", &(points[i].x), &(points[i].y)); } /* Funkce, která porovná souřadnice dvou bodů a vrátí, zda jsou menší, větší, nebo rovny. Použije se jako predikát pro * QuickSort. Vracíme záporné číslo, pokud je item1 < item2, kladné, pokud je item1 > item2 a nulu, pokud jsou si rovny. */ int compare(const void *item1, const void *item2) { struct spoint *p1 = (struct spoint*)item1; // Přetypujeme si ukazatele, aby se nám s nimi lépe pracovalo. struct spoint *p2 = (struct spoint*)item2; if (p1->x == p2->x) // X-ové souřadnice jsou stejné, takže porovnáme jen y-ové. return p1->y - p2->y; else return p1->x - p2->x; } /* Nalezne horní a dolní část konvexního obalu a vypše je do souboru. */ void process(void) { if (pointsCount == 0) return; struct spoint *resTop = malloc(pointsCount * sizeof(struct spoint)); // Horní část konvexního obalu. struct spoint *resBtm = malloc(pointsCount * sizeof(struct spoint)); // Spodní čast konvexního obalu. int resTopIdx = 0, resBtmIdx = 0; // Index posledního kůlu v poli resTop (resp. resBtm). int i = 1; // Index právě zpracovávaného kůlu. // Vložím počáteční bod do horní i dolní části konvexního obalu. resTop[0] = points[0]; resBtm[0] = points[0]; // Zpracujeme všechny kůly, které leží na stejné x-ové souřadnici, jako první bod. while((i < pointsCount) && (points[i].x == points[0].x)) resTop[++resTopIdx] = points[i++]; // Přidáme je jen do horní hranice. // Projdu v cyklu (ve správném pořadí) všechny kůly. while(i < pointsCount) { // Horní část konvexního obalu: vyhodíme všechny kůly, které porušují konvexitu s novým kůlem i. while((resTopIdx > 0) && !OK_FOR_TOP( resTop[resTopIdx-1], resTop[resTopIdx], points[i] ) ) resTopIdx--; // Přidáme kůl "i" do horní části. resTop[++resTopIdx] = points[i]; // Spodní část: vyhodíme všechny kůly, které porušují konvexitu s novým kůlem i. while((resBtmIdx > 0) && !OK_FOR_BOTTOM( resBtm[resBtmIdx-1], resBtm[resBtmIdx], points[i] ) ) resBtmIdx--; // Přidáme kůl "i" do spodní. resBtm[++resBtmIdx] = points[i]; i++; // Vezmem další kůl. } // Vypíšeme výsledky do souboru. FILE *fp = fopen("plot.out", "w"); fprintf(fp, "%d\n", resTopIdx + resBtmIdx); for(i = 0; i < resTopIdx; i++) // Vrchní čast vypíšeme normálně. fprintf(fp, "%d %d\n", resTop[i].x, resTop[i].y); for(i = resBtmIdx; i > 0; i--) // Spodní část vypíšeme pozpátku a bez posledního prvku. fprintf(fp, "%d %d\n", resBtm[i].x, resBtm[i].y); } int main(void) { load(); // Načteme souřadnice. qsort(points, pointsCount, sizeof(struct spoint), compare); process(); // Nalezneme konvexní obal a vypíšeme jej do souboru. return 0; }